Work-Commit
0
packages/vitec/Classes/DataProcessing/ContainerChildrenProcessor.php
Normal file → Executable file
0
packages/vitec/Classes/Domain/Model/Product.php
Normal file → Executable file
922
packages/vitec/Classes/Domain/Model/Product.php.bak.20260529111828
Executable file
@@ -0,0 +1,922 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Domain\Model;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||||
|
use TYPO3\CMS\Extbase\Domain\Model\Category;
|
||||||
|
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product
|
||||||
|
*/
|
||||||
|
class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* title
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||||
|
*/
|
||||||
|
protected $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slug
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $slug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* urltitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $urltitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* seotitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $seotitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* seometa
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $seometa = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* keywords
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $keywords = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* structureddata
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $structureddata = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* teaser
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $teaser = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subtitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $subtitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* video
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $video = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonapp
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonapp = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonwebsite
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonwebsite = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideondatasheets
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideondatasheets = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonproducts
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonproducts = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* applications
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $applications = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* description
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* highlights
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $highlights = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shortcut
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $shortcut = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shortcutpid
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $shortcutpid = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* legacy
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $legacy = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* supportproduct
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $supportproduct = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subproduct
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $subproduct = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectStorage<Category>
|
||||||
|
*/
|
||||||
|
protected $categories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product images
|
||||||
|
*
|
||||||
|
* @var ObjectStorage<FileReference>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $productimage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads
|
||||||
|
*
|
||||||
|
* @var ObjectStorage<\Evomedien\Vitec\Domain\Model\Download>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $downloads;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Graph Image
|
||||||
|
*
|
||||||
|
* @var FileReference
|
||||||
|
*/
|
||||||
|
protected $ogimage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content element link - Key Features
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentelement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content element link - CTA Features
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentelementcta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Evomedien\Vitec\Domain\Model\Product>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Lazy
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $relatedprodukt;
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title
|
||||||
|
*
|
||||||
|
* @param string $title
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setTitle(string $title)
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the video
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getVideo()
|
||||||
|
{
|
||||||
|
return $this->video;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the video
|
||||||
|
*
|
||||||
|
* @param string $video
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setVideo(string $video)
|
||||||
|
{
|
||||||
|
$this->video = $video;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the slug
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the slug
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSlug(string $slug)
|
||||||
|
{
|
||||||
|
$this->slug = $slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the urltitle
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUrltitle()
|
||||||
|
{
|
||||||
|
return $this->urltitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the urltitle
|
||||||
|
*
|
||||||
|
* @param string $urltitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUrltitle(string $urltitle)
|
||||||
|
{
|
||||||
|
$this->urltitle = $urltitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seotitle
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSeotitle()
|
||||||
|
{
|
||||||
|
return $this->seotitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the seotitle
|
||||||
|
*
|
||||||
|
* @param string $seotitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSeotitle(string $seotitle)
|
||||||
|
{
|
||||||
|
$this->seotitle = $seotitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seometa
|
||||||
|
*
|
||||||
|
* @return string $seometa
|
||||||
|
*/
|
||||||
|
public function getSeometa()
|
||||||
|
{
|
||||||
|
return $this->seometa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the seometa
|
||||||
|
*
|
||||||
|
* @param string $seometa
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSeometa($seometa)
|
||||||
|
{
|
||||||
|
$this->seometa = $seometa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the keywords
|
||||||
|
*
|
||||||
|
* @return string $keywords
|
||||||
|
*/
|
||||||
|
public function getKeywords()
|
||||||
|
{
|
||||||
|
return $this->keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the keywords
|
||||||
|
*
|
||||||
|
* @param string $keywords
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setKeywords($keywords)
|
||||||
|
{
|
||||||
|
$this->keywords = $keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the teaser
|
||||||
|
*
|
||||||
|
* @return string $kteasereywords
|
||||||
|
*/
|
||||||
|
public function getTeaser()
|
||||||
|
{
|
||||||
|
return $this->teaser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the teaser
|
||||||
|
*
|
||||||
|
* @param string $teaser
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setTeaser($teaser)
|
||||||
|
{
|
||||||
|
$this->teaser = $teaser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subtitle
|
||||||
|
*
|
||||||
|
* @return string $subtitle
|
||||||
|
*/
|
||||||
|
public function getSubtitle()
|
||||||
|
{
|
||||||
|
return $this->subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the subtitle
|
||||||
|
*
|
||||||
|
* @param string $subtitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSubtitle($subtitle)
|
||||||
|
{
|
||||||
|
$this->subtitle = $subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonapp
|
||||||
|
*
|
||||||
|
* @return bool $hideonapp
|
||||||
|
*/
|
||||||
|
public function getHideonapp()
|
||||||
|
{
|
||||||
|
return $this->hideonapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonapp
|
||||||
|
*
|
||||||
|
* @param bool $hideonapp
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonapp($hideonapp)
|
||||||
|
{
|
||||||
|
$this->hideonapp = $hideonapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description
|
||||||
|
*
|
||||||
|
* @return bool $description
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description
|
||||||
|
*
|
||||||
|
* @param bool $description
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDescriptionp($description)
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonwebsite
|
||||||
|
*
|
||||||
|
* @return bool $hideonwebsite
|
||||||
|
*/
|
||||||
|
public function getHideonwebsite()
|
||||||
|
{
|
||||||
|
return $this->hideonwebsite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonwebsite
|
||||||
|
*
|
||||||
|
* @param bool $hideonwebsite
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonwebsite($hideonwebsite)
|
||||||
|
{
|
||||||
|
$this->hideonwebsite = $hideonwebsite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideondatasheets
|
||||||
|
*
|
||||||
|
* @return bool $hideondatasheets
|
||||||
|
*/
|
||||||
|
public function getHideondatasheets()
|
||||||
|
{
|
||||||
|
return $this->hideondatasheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideondatasheets
|
||||||
|
*
|
||||||
|
* @param bool $hideondatasheets
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideondatasheets($hideondatasheets)
|
||||||
|
{
|
||||||
|
$this->hideondatasheets = $hideondatasheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonproducts
|
||||||
|
*
|
||||||
|
* @return bool $hideonproducts
|
||||||
|
*/
|
||||||
|
public function getHideonproducts()
|
||||||
|
{
|
||||||
|
return $this->hideonproducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonproducts
|
||||||
|
*
|
||||||
|
* @param bool $hideonproducts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonproducts($hideonproducts)
|
||||||
|
{
|
||||||
|
$this->hideonproducts = $hideonproducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the structureddata
|
||||||
|
*
|
||||||
|
* @return string $structureddata
|
||||||
|
*/
|
||||||
|
public function getStructureddata()
|
||||||
|
{
|
||||||
|
return $this->structureddata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the structureddata
|
||||||
|
*
|
||||||
|
* @param string $structureddata
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setStructureddata($structureddata)
|
||||||
|
{
|
||||||
|
$this->structureddata = $structureddata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the applications
|
||||||
|
*
|
||||||
|
* @return string $applications
|
||||||
|
*/
|
||||||
|
public function getApplications()
|
||||||
|
{
|
||||||
|
return $this->applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the applications
|
||||||
|
*
|
||||||
|
* @param string $applications
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApplications($applications)
|
||||||
|
{
|
||||||
|
$this->applications = $applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highlights
|
||||||
|
*
|
||||||
|
* @return string $highlights
|
||||||
|
*/
|
||||||
|
public function getHighlights()
|
||||||
|
{
|
||||||
|
return $this->highlights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the highlights
|
||||||
|
*
|
||||||
|
* @param string $highlights
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHighlights($highlights)
|
||||||
|
{
|
||||||
|
$this->highlights = $highlights;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the shortcutpid
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getShortcutpid()
|
||||||
|
{
|
||||||
|
return $this->shortcutpid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shortcutpid
|
||||||
|
*
|
||||||
|
* @param string $shortcutpid
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setShortcutpid ($shortcutpid)
|
||||||
|
{
|
||||||
|
$this->shortcutpid = $shortcutpid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the shortcut
|
||||||
|
*
|
||||||
|
* @return bool $shortcut
|
||||||
|
*/
|
||||||
|
public function getShortcut()
|
||||||
|
{
|
||||||
|
return $this->shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shortcut
|
||||||
|
*
|
||||||
|
* @param bool $shortcut
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setShortcut($shortcut)
|
||||||
|
{
|
||||||
|
$this->shortcut = $shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the legacy
|
||||||
|
*
|
||||||
|
* @return bool $legacy
|
||||||
|
*/
|
||||||
|
public function getLegacy()
|
||||||
|
{
|
||||||
|
return $this->legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the legacy
|
||||||
|
*
|
||||||
|
* @param bool $legacy
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setLegacy($legacy)
|
||||||
|
{
|
||||||
|
$this->legacy = $legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the supportproduct
|
||||||
|
*
|
||||||
|
* @return bool $supportproduct
|
||||||
|
*/
|
||||||
|
public function getSupportproduct()
|
||||||
|
{
|
||||||
|
return $this->supportproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the supportproduct
|
||||||
|
*
|
||||||
|
* @param bool $supportproduct
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSupportproduct($supportproduct)
|
||||||
|
{
|
||||||
|
$this->supportproduct = $supportproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subproduct
|
||||||
|
*
|
||||||
|
* @return bool $subproduct
|
||||||
|
*/
|
||||||
|
public function getSubproduct()
|
||||||
|
{
|
||||||
|
return $this->subproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the subproduct
|
||||||
|
*
|
||||||
|
* @param bool $subproduct
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSubproduct($subproduct)
|
||||||
|
{
|
||||||
|
$this->subproduct = $subproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the ObjectStorage for categories
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->categories = new ObjectStorage();
|
||||||
|
$this->productimage = new ObjectStorage();
|
||||||
|
$this->downloads = new ObjectStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a category
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addCategory(Category $category)
|
||||||
|
{
|
||||||
|
$this->categories->attach($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a category
|
||||||
|
*
|
||||||
|
* @param Category $categoryToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeCategory(Category $categoryToRemove)
|
||||||
|
{
|
||||||
|
$this->categories->detach($categoryToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the categories
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<Category>
|
||||||
|
*/
|
||||||
|
public function getCategories()
|
||||||
|
{
|
||||||
|
return $this->categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the categories
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<Category> $categories
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setCategories(ObjectStorage $categories)
|
||||||
|
{
|
||||||
|
$this->categories = $categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a product image
|
||||||
|
*
|
||||||
|
* @param FileReference $productimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addProductimage(FileReference $productimage)
|
||||||
|
{
|
||||||
|
$this->productimage->attach($productimage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a product image
|
||||||
|
*
|
||||||
|
* @param FileReference $productimageToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeProductimage(FileReference $productimageToRemove)
|
||||||
|
{
|
||||||
|
$this->productimage->detach($productimageToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product images
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<FileReference>
|
||||||
|
*/
|
||||||
|
public function getProductimage()
|
||||||
|
{
|
||||||
|
return $this->productimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product images
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<FileReference> $productimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setProductimage(ObjectStorage $productimage)
|
||||||
|
{
|
||||||
|
$this->productimage = $productimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a download
|
||||||
|
*
|
||||||
|
* @param \Evomedien\Vitec\Domain\Model\Download $download
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addDownload(\Evomedien\Vitec\Domain\Model\Download $download): void
|
||||||
|
{
|
||||||
|
$this->downloads->attach($download);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a download
|
||||||
|
*
|
||||||
|
* @param \Evomedien\Vitec\Domain\Model\Download $downloadToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeDownload(\Evomedien\Vitec\Domain\Model\Download $downloadToRemove): void
|
||||||
|
{
|
||||||
|
$this->downloads->detach($downloadToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the downloads
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<\Evomedien\Vitec\Domain\Model\Download>
|
||||||
|
*/
|
||||||
|
public function getDownloads(): ObjectStorage
|
||||||
|
{
|
||||||
|
return $this->downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the downloads
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<\Evomedien\Vitec\Domain\Model\Download> $downloads
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDownloads(ObjectStorage $downloads): void
|
||||||
|
{
|
||||||
|
$this->downloads = $downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Open Graph Image
|
||||||
|
*
|
||||||
|
* @return FileReference|null
|
||||||
|
*/
|
||||||
|
public function getOgimage(): ?FileReference
|
||||||
|
{
|
||||||
|
return $this->ogimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Open Graph Image
|
||||||
|
*
|
||||||
|
* @param FileReference $ogimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOgimage(FileReference $ogimage): void
|
||||||
|
{
|
||||||
|
$this->ogimage = $ogimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content element link
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContentelement(): string
|
||||||
|
{
|
||||||
|
return $this->contentelement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the content element link
|
||||||
|
*
|
||||||
|
* @param string $contentelement
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setContentelement(string $contentelement): void
|
||||||
|
{
|
||||||
|
$this->contentelement = $contentelement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content element cta link
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContentelementcta(): string
|
||||||
|
{
|
||||||
|
return $this->contentelementcta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the content element link cta
|
||||||
|
*
|
||||||
|
* @param string $contentelementcta
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setContentelementcta(string $contentelementcta): void
|
||||||
|
{
|
||||||
|
$this->contentelementcta = $contentelementcta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\Product>
|
||||||
|
*/
|
||||||
|
public function getRelatedprodukt(): \TYPO3\CMS\Extbase\Persistence\ObjectStorage
|
||||||
|
{
|
||||||
|
return $this->relatedprodukt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\Product> $relatedprodukt
|
||||||
|
*/
|
||||||
|
public function setRelatedprodukt(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relatedprodukt): void
|
||||||
|
{
|
||||||
|
$this->relatedprodukt = $relatedprodukt;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
}
|
||||||
952
packages/vitec/Classes/Domain/Model/Product.php.bak.20260529120751
Executable file
@@ -0,0 +1,952 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Domain\Model;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||||
|
use TYPO3\CMS\Extbase\Domain\Model\Category;
|
||||||
|
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product
|
||||||
|
*/
|
||||||
|
class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* title
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||||
|
*/
|
||||||
|
protected $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slug
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $slug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* urltitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $urltitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* seotitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $seotitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* seometa
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $seometa = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* keywords
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $keywords = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* structureddata
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $structureddata = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* teaser
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $teaser = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subtitle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $subtitle = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* video
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $video = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonapp
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonapp = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonwebsite
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonwebsite = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideondatasheets
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideondatasheets = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hideonproducts
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $hideonproducts = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* applications
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $applications = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* description
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* highlights
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $highlights = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shortcut
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $shortcut = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shortcutpid
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $shortcutpid = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* legacy
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $legacy = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* supportproduct
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $supportproduct = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subproduct
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $subproduct = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectStorage<Category>
|
||||||
|
*/
|
||||||
|
protected $categories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product images
|
||||||
|
*
|
||||||
|
* @var ObjectStorage<FileReference>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $productimage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads
|
||||||
|
*
|
||||||
|
* @var ObjectStorage<\Evomedien\Vitec\Domain\Model\Download>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $downloads;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Graph Image
|
||||||
|
*
|
||||||
|
* @var FileReference
|
||||||
|
*/
|
||||||
|
protected $ogimage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content element link - Key Features
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploaded / locally selected video file (FAL)
|
||||||
|
*
|
||||||
|
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference|null
|
||||||
|
*/
|
||||||
|
protected $videofile;
|
||||||
|
|
||||||
|
protected $contentelement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content element link - CTA Features
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $contentelementcta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Evomedien\Vitec\Domain\Model\Product>
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Lazy
|
||||||
|
* @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
|
||||||
|
*/
|
||||||
|
protected $relatedprodukt;
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title
|
||||||
|
*
|
||||||
|
* @param string $title
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setTitle(string $title)
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the video
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getVideo()
|
||||||
|
{
|
||||||
|
return $this->video;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the video
|
||||||
|
*
|
||||||
|
* @param string $video
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setVideo(string $video)
|
||||||
|
{
|
||||||
|
$this->video = $video;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the slug
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the slug
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSlug(string $slug)
|
||||||
|
{
|
||||||
|
$this->slug = $slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the urltitle
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUrltitle()
|
||||||
|
{
|
||||||
|
return $this->urltitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the urltitle
|
||||||
|
*
|
||||||
|
* @param string $urltitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUrltitle(string $urltitle)
|
||||||
|
{
|
||||||
|
$this->urltitle = $urltitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seotitle
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSeotitle()
|
||||||
|
{
|
||||||
|
return $this->seotitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the seotitle
|
||||||
|
*
|
||||||
|
* @param string $seotitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSeotitle(string $seotitle)
|
||||||
|
{
|
||||||
|
$this->seotitle = $seotitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seometa
|
||||||
|
*
|
||||||
|
* @return string $seometa
|
||||||
|
*/
|
||||||
|
public function getSeometa()
|
||||||
|
{
|
||||||
|
return $this->seometa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the seometa
|
||||||
|
*
|
||||||
|
* @param string $seometa
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSeometa($seometa)
|
||||||
|
{
|
||||||
|
$this->seometa = $seometa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the keywords
|
||||||
|
*
|
||||||
|
* @return string $keywords
|
||||||
|
*/
|
||||||
|
public function getKeywords()
|
||||||
|
{
|
||||||
|
return $this->keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the keywords
|
||||||
|
*
|
||||||
|
* @param string $keywords
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setKeywords($keywords)
|
||||||
|
{
|
||||||
|
$this->keywords = $keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the teaser
|
||||||
|
*
|
||||||
|
* @return string $kteasereywords
|
||||||
|
*/
|
||||||
|
public function getTeaser()
|
||||||
|
{
|
||||||
|
return $this->teaser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the teaser
|
||||||
|
*
|
||||||
|
* @param string $teaser
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setTeaser($teaser)
|
||||||
|
{
|
||||||
|
$this->teaser = $teaser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subtitle
|
||||||
|
*
|
||||||
|
* @return string $subtitle
|
||||||
|
*/
|
||||||
|
public function getSubtitle()
|
||||||
|
{
|
||||||
|
return $this->subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the subtitle
|
||||||
|
*
|
||||||
|
* @param string $subtitle
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSubtitle($subtitle)
|
||||||
|
{
|
||||||
|
$this->subtitle = $subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonapp
|
||||||
|
*
|
||||||
|
* @return bool $hideonapp
|
||||||
|
*/
|
||||||
|
public function getHideonapp()
|
||||||
|
{
|
||||||
|
return $this->hideonapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonapp
|
||||||
|
*
|
||||||
|
* @param bool $hideonapp
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonapp($hideonapp)
|
||||||
|
{
|
||||||
|
$this->hideonapp = $hideonapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description
|
||||||
|
*
|
||||||
|
* @return bool $description
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description
|
||||||
|
*
|
||||||
|
* @param bool $description
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDescriptionp($description)
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonwebsite
|
||||||
|
*
|
||||||
|
* @return bool $hideonwebsite
|
||||||
|
*/
|
||||||
|
public function getHideonwebsite()
|
||||||
|
{
|
||||||
|
return $this->hideonwebsite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonwebsite
|
||||||
|
*
|
||||||
|
* @param bool $hideonwebsite
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonwebsite($hideonwebsite)
|
||||||
|
{
|
||||||
|
$this->hideonwebsite = $hideonwebsite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideondatasheets
|
||||||
|
*
|
||||||
|
* @return bool $hideondatasheets
|
||||||
|
*/
|
||||||
|
public function getHideondatasheets()
|
||||||
|
{
|
||||||
|
return $this->hideondatasheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideondatasheets
|
||||||
|
*
|
||||||
|
* @param bool $hideondatasheets
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideondatasheets($hideondatasheets)
|
||||||
|
{
|
||||||
|
$this->hideondatasheets = $hideondatasheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hideonproducts
|
||||||
|
*
|
||||||
|
* @return bool $hideonproducts
|
||||||
|
*/
|
||||||
|
public function getHideonproducts()
|
||||||
|
{
|
||||||
|
return $this->hideonproducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hideonproducts
|
||||||
|
*
|
||||||
|
* @param bool $hideonproducts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHideonproducts($hideonproducts)
|
||||||
|
{
|
||||||
|
$this->hideonproducts = $hideonproducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the structureddata
|
||||||
|
*
|
||||||
|
* @return string $structureddata
|
||||||
|
*/
|
||||||
|
public function getStructureddata()
|
||||||
|
{
|
||||||
|
return $this->structureddata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the structureddata
|
||||||
|
*
|
||||||
|
* @param string $structureddata
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setStructureddata($structureddata)
|
||||||
|
{
|
||||||
|
$this->structureddata = $structureddata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the applications
|
||||||
|
*
|
||||||
|
* @return string $applications
|
||||||
|
*/
|
||||||
|
public function getApplications()
|
||||||
|
{
|
||||||
|
return $this->applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the applications
|
||||||
|
*
|
||||||
|
* @param string $applications
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApplications($applications)
|
||||||
|
{
|
||||||
|
$this->applications = $applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highlights
|
||||||
|
*
|
||||||
|
* @return string $highlights
|
||||||
|
*/
|
||||||
|
public function getHighlights()
|
||||||
|
{
|
||||||
|
return $this->highlights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the highlights
|
||||||
|
*
|
||||||
|
* @param string $highlights
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHighlights($highlights)
|
||||||
|
{
|
||||||
|
$this->highlights = $highlights;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the shortcutpid
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getShortcutpid()
|
||||||
|
{
|
||||||
|
return $this->shortcutpid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shortcutpid
|
||||||
|
*
|
||||||
|
* @param string $shortcutpid
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setShortcutpid ($shortcutpid)
|
||||||
|
{
|
||||||
|
$this->shortcutpid = $shortcutpid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the shortcut
|
||||||
|
*
|
||||||
|
* @return bool $shortcut
|
||||||
|
*/
|
||||||
|
public function getShortcut()
|
||||||
|
{
|
||||||
|
return $this->shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shortcut
|
||||||
|
*
|
||||||
|
* @param bool $shortcut
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setShortcut($shortcut)
|
||||||
|
{
|
||||||
|
$this->shortcut = $shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the legacy
|
||||||
|
*
|
||||||
|
* @return bool $legacy
|
||||||
|
*/
|
||||||
|
public function getLegacy()
|
||||||
|
{
|
||||||
|
return $this->legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the legacy
|
||||||
|
*
|
||||||
|
* @param bool $legacy
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setLegacy($legacy)
|
||||||
|
{
|
||||||
|
$this->legacy = $legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the supportproduct
|
||||||
|
*
|
||||||
|
* @return bool $supportproduct
|
||||||
|
*/
|
||||||
|
public function getSupportproduct()
|
||||||
|
{
|
||||||
|
return $this->supportproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the supportproduct
|
||||||
|
*
|
||||||
|
* @param bool $supportproduct
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSupportproduct($supportproduct)
|
||||||
|
{
|
||||||
|
$this->supportproduct = $supportproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subproduct
|
||||||
|
*
|
||||||
|
* @return bool $subproduct
|
||||||
|
*/
|
||||||
|
public function getSubproduct()
|
||||||
|
{
|
||||||
|
return $this->subproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the subproduct
|
||||||
|
*
|
||||||
|
* @param bool $subproduct
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setSubproduct($subproduct)
|
||||||
|
{
|
||||||
|
$this->subproduct = $subproduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the ObjectStorage for categories
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->categories = new ObjectStorage();
|
||||||
|
$this->productimage = new ObjectStorage();
|
||||||
|
$this->downloads = new ObjectStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a category
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addCategory(Category $category)
|
||||||
|
{
|
||||||
|
$this->categories->attach($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a category
|
||||||
|
*
|
||||||
|
* @param Category $categoryToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeCategory(Category $categoryToRemove)
|
||||||
|
{
|
||||||
|
$this->categories->detach($categoryToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the categories
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<Category>
|
||||||
|
*/
|
||||||
|
public function getCategories()
|
||||||
|
{
|
||||||
|
return $this->categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the categories
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<Category> $categories
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setCategories(ObjectStorage $categories)
|
||||||
|
{
|
||||||
|
$this->categories = $categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a product image
|
||||||
|
*
|
||||||
|
* @param FileReference $productimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addProductimage(FileReference $productimage)
|
||||||
|
{
|
||||||
|
$this->productimage->attach($productimage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a product image
|
||||||
|
*
|
||||||
|
* @param FileReference $productimageToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeProductimage(FileReference $productimageToRemove)
|
||||||
|
{
|
||||||
|
$this->productimage->detach($productimageToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product images
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<FileReference>
|
||||||
|
*/
|
||||||
|
public function getProductimage()
|
||||||
|
{
|
||||||
|
return $this->productimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product images
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<FileReference> $productimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setProductimage(ObjectStorage $productimage)
|
||||||
|
{
|
||||||
|
$this->productimage = $productimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a download
|
||||||
|
*
|
||||||
|
* @param \Evomedien\Vitec\Domain\Model\Download $download
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addDownload(\Evomedien\Vitec\Domain\Model\Download $download): void
|
||||||
|
{
|
||||||
|
$this->downloads->attach($download);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a download
|
||||||
|
*
|
||||||
|
* @param \Evomedien\Vitec\Domain\Model\Download $downloadToRemove
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeDownload(\Evomedien\Vitec\Domain\Model\Download $downloadToRemove): void
|
||||||
|
{
|
||||||
|
$this->downloads->detach($downloadToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the downloads
|
||||||
|
*
|
||||||
|
* @return ObjectStorage<\Evomedien\Vitec\Domain\Model\Download>
|
||||||
|
*/
|
||||||
|
public function getDownloads(): ObjectStorage
|
||||||
|
{
|
||||||
|
return $this->downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the downloads
|
||||||
|
*
|
||||||
|
* @param ObjectStorage<\Evomedien\Vitec\Domain\Model\Download> $downloads
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDownloads(ObjectStorage $downloads): void
|
||||||
|
{
|
||||||
|
$this->downloads = $downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Open Graph Image
|
||||||
|
*
|
||||||
|
* @return FileReference|null
|
||||||
|
*/
|
||||||
|
public function getOgimage(): ?FileReference
|
||||||
|
{
|
||||||
|
return $this->ogimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Open Graph Image
|
||||||
|
*
|
||||||
|
* @param FileReference $ogimage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOgimage(FileReference $ogimage): void
|
||||||
|
{
|
||||||
|
$this->ogimage = $ogimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content element link
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the uploaded video file
|
||||||
|
*
|
||||||
|
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference|null
|
||||||
|
*/
|
||||||
|
public function getVideofile(): ?\TYPO3\CMS\Extbase\Domain\Model\FileReference
|
||||||
|
{
|
||||||
|
return $this->videofile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the uploaded video file
|
||||||
|
*
|
||||||
|
* @param \TYPO3\CMS\Extbase\Domain\Model\FileReference|null $videofile
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setVideofile(?\TYPO3\CMS\Extbase\Domain\Model\FileReference $videofile): void
|
||||||
|
{
|
||||||
|
$this->videofile = $videofile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContentelement(): string
|
||||||
|
{
|
||||||
|
return $this->contentelement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the content element link
|
||||||
|
*
|
||||||
|
* @param string $contentelement
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setContentelement(string $contentelement): void
|
||||||
|
{
|
||||||
|
$this->contentelement = $contentelement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content element cta link
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContentelementcta(): string
|
||||||
|
{
|
||||||
|
return $this->contentelementcta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the content element link cta
|
||||||
|
*
|
||||||
|
* @param string $contentelementcta
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setContentelementcta(string $contentelementcta): void
|
||||||
|
{
|
||||||
|
$this->contentelementcta = $contentelementcta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\Product>
|
||||||
|
*/
|
||||||
|
public function getRelatedprodukt(): \TYPO3\CMS\Extbase\Persistence\ObjectStorage
|
||||||
|
{
|
||||||
|
return $this->relatedprodukt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\Product> $relatedprodukt
|
||||||
|
*/
|
||||||
|
public function setRelatedprodukt(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relatedprodukt): void
|
||||||
|
{
|
||||||
|
$this->relatedprodukt = $relatedprodukt;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
}
|
||||||
0
packages/vitec/Classes/EventListener/ShowFrontendLayoutBanner.php
Normal file → Executable file
0
packages/vitec/Classes/Hook/SyncBackendLayoutHook.php
Normal file → Executable file
0
packages/vitec/Classes/Service/ContentElementResolver.php
Normal file → Executable file
238
packages/vitec/Classes/Service/ContentElementResolver.php.bak.20260529120325
Executable file
@@ -0,0 +1,238 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Service;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a TYPO3 typolink string (as stored by `inputLink` fields like
|
||||||
|
* Product.contentelement / Product.contentelementcta) to the JSON
|
||||||
|
* representation of the referenced tt_content element.
|
||||||
|
*
|
||||||
|
* Mirrors the shape produced by
|
||||||
|
* {@see \Evomedien\Vitec\DataProcessing\ContainerChildrenProcessor}:
|
||||||
|
* { id, type, colPos, sorting, appearance, data }
|
||||||
|
*
|
||||||
|
* Nested VITEC list-plugins are resolved through their `renderForRecord()`
|
||||||
|
* just like container children, so a referenced productlist / productshow /
|
||||||
|
* usecaselist / usecaseshow appears with its full headless JSON in `data`.
|
||||||
|
*
|
||||||
|
* Exception-safe: every public entry point returns `null` on any failure
|
||||||
|
* so the surrounding JSON output stays clean.
|
||||||
|
*/
|
||||||
|
final class ContentElementResolver
|
||||||
|
{
|
||||||
|
/** Fields that go to the envelope (not to `data`). */
|
||||||
|
private const ENVELOPE = [
|
||||||
|
'uid', 'CType', 'colPos', 'sorting',
|
||||||
|
'layout', 'frame_class', 'space_before_class', 'space_after_class',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Technical / system / TCA-default fields — never sent to frontend. */
|
||||||
|
private const SYSTEM_FIELDS = [
|
||||||
|
'pid', 'sys_language_uid', 'l18n_parent', 'l18n_diffsource',
|
||||||
|
'l10n_source', 'l10n_state', 'l10n_parent',
|
||||||
|
't3_origuid', 'tx_impexp_origuid',
|
||||||
|
'tx_container_parent',
|
||||||
|
'tstamp', 'crdate', 'cruser_id',
|
||||||
|
'hidden', 'deleted', 'starttime', 'endtime', 'fe_group',
|
||||||
|
't3ver_oid', 't3ver_wsid', 't3ver_state', 't3ver_stage',
|
||||||
|
't3ver_id', 't3ver_label', 't3ver_count', 't3ver_tstamp',
|
||||||
|
'editlock', 'sorting_foreign', 'rowDescription',
|
||||||
|
'spaceBefore', 'spaceAfter',
|
||||||
|
'imagecols', 'sectionIndex', 'linkToTop', 'recursive', 'date',
|
||||||
|
'bullets_type', 'cols',
|
||||||
|
'table_delimiter', 'table_enclosure', 'table_header_position',
|
||||||
|
'table_tfoot', 'table_caption',
|
||||||
|
'filelink_size', 'filelink_sorting', 'filelink_sorting_direction',
|
||||||
|
'uploads_description', 'uploads_type',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const KEEP_IF_ZERO = ['header_layout'];
|
||||||
|
|
||||||
|
private const PLUGIN_RENDERERS = [
|
||||||
|
'vitec_productlist' => [ProductListJsonRenderer::class, 'products'],
|
||||||
|
'vitec_productshow' => [ProductShowJsonRenderer::class, 'product'],
|
||||||
|
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
|
||||||
|
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a typolink string to a normalised tt_content JSON element.
|
||||||
|
*
|
||||||
|
* Accepted forms:
|
||||||
|
* - "t3://record?identifier=tt_content&uid=N"
|
||||||
|
* - "<numeric>" (legacy: bare tt_content uid)
|
||||||
|
* - everything else → null (page links etc.)
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
public static function resolveLink(?string $link): ?array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$link = trim((string)$link);
|
||||||
|
if ($link === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uid = self::extractTtContentUid($link);
|
||||||
|
if ($uid <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
$row = $qb
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('uid', $qb->createNamedParameter($uid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::normaliseRecord($row);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalise a tt_content DB row to the same envelope shape that
|
||||||
|
* {@see \Evomedien\Vitec\DataProcessing\ContainerChildrenProcessor}
|
||||||
|
* emits for container children. VITEC list-plugin children are
|
||||||
|
* resolved to their headless JSON.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $record
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public static function normaliseRecord(array $record): array
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
foreach ($record as $field => $value) {
|
||||||
|
if (in_array($field, self::ENVELOPE, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (in_array($field, self::SYSTEM_FIELDS, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (self::isEmpty($value) && !in_array($field, self::KEEP_IF_ZERO, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$data[$field] = self::castValue($field, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::resolvePluginData($record, $data);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => (int)$record['uid'],
|
||||||
|
'type' => (string)$record['CType'],
|
||||||
|
'colPos' => (int)($record['colPos'] ?? 0),
|
||||||
|
'sorting' => (int)($record['sorting'] ?? 0),
|
||||||
|
'appearance' => [
|
||||||
|
'layout' => (string)($record['layout'] ?? ''),
|
||||||
|
'frameClass' => (string)($record['frame_class'] ?? 'default'),
|
||||||
|
'spaceBefore' => (string)($record['space_before_class'] ?? ''),
|
||||||
|
'spaceAfter' => (string)($record['space_after_class'] ?? ''),
|
||||||
|
],
|
||||||
|
'data' => (object)$data,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the tt_content uid from a typolink string.
|
||||||
|
*/
|
||||||
|
private static function extractTtContentUid(string $link): int
|
||||||
|
{
|
||||||
|
if (ctype_digit($link)) {
|
||||||
|
return (int)$link;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str_starts_with($link, 't3://record')) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($link);
|
||||||
|
if (empty($parts['query'])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = [];
|
||||||
|
parse_str((string)$parts['query'], $params);
|
||||||
|
|
||||||
|
$identifier = (string)($params['identifier'] ?? '');
|
||||||
|
$uid = (int)($params['uid'] ?? 0);
|
||||||
|
|
||||||
|
if ($identifier !== 'tt_content' || $uid <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the record is a VITEC list-plugin, run its renderer for THIS row
|
||||||
|
* and inject the decoded result under its key. Drops raw pi_flexform.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $record
|
||||||
|
* @param array<string,mixed> $data
|
||||||
|
*/
|
||||||
|
private static function resolvePluginData(array $record, array &$data): void
|
||||||
|
{
|
||||||
|
$listType = (string)($record['list_type'] ?? '');
|
||||||
|
if ($listType === '' || !isset(self::PLUGIN_RENDERERS[$listType])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
[$rendererClass, $jsonKey] = self::PLUGIN_RENDERERS[$listType];
|
||||||
|
$renderer = GeneralUtility::makeInstance($rendererClass);
|
||||||
|
|
||||||
|
if (!method_exists($renderer, 'renderForRecord')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = $renderer->renderForRecord($record);
|
||||||
|
if ($json === '' || $json === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode($json, true);
|
||||||
|
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[$jsonKey] = $decoded;
|
||||||
|
unset($data['pi_flexform']);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// leave raw data on failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isEmpty(mixed $value): bool
|
||||||
|
{
|
||||||
|
return $value === null || $value === '' || $value === 0 || $value === '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function castValue(string $field, mixed $value): mixed
|
||||||
|
{
|
||||||
|
if (in_array($field, ['header_layout'], true)) {
|
||||||
|
return (int)$value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages/vitec/Classes/UserFunc/ProductListJsonRenderer.php
Normal file → Executable file
463
packages/vitec/Classes/UserFunc/ProductListJsonRenderer.php.bak.20260529111828
Executable file
@@ -0,0 +1,463 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use Evomedien\Vitec\Domain\Repository\ProductRepository;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render product list as JSON for headless.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (used for top-level list plugins via
|
||||||
|
* TypoScript). `renderForRecord()` processes one specific tt_content row and
|
||||||
|
* is used both internally and by ContainerChildrenProcessor to resolve a
|
||||||
|
* product-list plugin nested inside a b13 container.
|
||||||
|
*/
|
||||||
|
class ProductListJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productlist', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
// Not a product-list page: emit nothing so headless removes the key.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-list plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement tt_content row of the plugin
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Parse FlexForm of THIS element
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$categoryUids = array_filter(
|
||||||
|
array_map('intval', explode(',', (string)($settings['categories'] ?? '')))
|
||||||
|
);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$allProducts = (bool)($settings['allproducts'] ?? false);
|
||||||
|
|
||||||
|
// Extbase repositories don't work in UserFunc context — direct query.
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productQuery = $productQueryBuilder
|
||||||
|
->select('p.*')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hidden', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.legacy', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.supportproduct', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonwebsite', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonproducts', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.subproduct', 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($categoryUids) && !$allProducts) {
|
||||||
|
$productQuery
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid AND mm.tablenames = ' . $productQueryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) . ' AND mm.fieldname = ' . $productQueryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->andWhere(
|
||||||
|
$productQueryBuilder->expr()->in('mm.uid_local', $productQueryBuilder->createNamedParameter($categoryUids, Connection::PARAM_INT_ARRAY))
|
||||||
|
)
|
||||||
|
->groupBy('p.uid');
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $productQuery->executeQuery()->fetchAllAssociative();
|
||||||
|
|
||||||
|
$productsData = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productsData[] = $this->serializeProduct($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
return json_encode([
|
||||||
|
'products' => $productsData,
|
||||||
|
'debug' => [
|
||||||
|
'pageId' => (int)($GLOBALS['TSFE']->id ?? 0),
|
||||||
|
'categoryUids' => $categoryUids,
|
||||||
|
'productCount' => count($productsData),
|
||||||
|
'settings' => $settings,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($productsData);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a single product DB row to the full headless JSON structure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||||
|
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||||
|
|
||||||
|
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||||
|
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.uid_local', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
|
||||||
|
$images = [];
|
||||||
|
foreach ($fileReferences as $fileRefData) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$sizes = [
|
||||||
|
'small' => ['width' => 400, 'height' => null],
|
||||||
|
'medium' => ['width' => 800, 'height' => null],
|
||||||
|
'large' => ['width' => 1200, 'height' => null],
|
||||||
|
'xlarge' => ['width' => 1600, 'height' => null],
|
||||||
|
];
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ($sizes as $sizeName => $dimensions) {
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
[
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'height' => $dimensions['height'],
|
||||||
|
'crop' => $fileRefData['crop'] ?? null
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$imageUri = $imageService->getImageUri($processedImage);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageUri,
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'descriptor' => $dimensions['width'] . 'w'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultProcessed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 800, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($defaultProcessed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type')
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRefData = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRefData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$processed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductCategories(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(static function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'] ?? '',
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
507
packages/vitec/Classes/UserFunc/ProductListJsonRenderer.php.bak.20260529115809
Executable file
@@ -0,0 +1,507 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use Evomedien\Vitec\Domain\Repository\ProductRepository;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render product list as JSON for headless.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (used for top-level list plugins via
|
||||||
|
* TypoScript). `renderForRecord()` processes one specific tt_content row and
|
||||||
|
* is used both internally and by ContainerChildrenProcessor to resolve a
|
||||||
|
* product-list plugin nested inside a b13 container.
|
||||||
|
*/
|
||||||
|
class ProductListJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productlist', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
// Not a product-list page: emit nothing so headless removes the key.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-list plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement tt_content row of the plugin
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Parse FlexForm of THIS element
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$categoryUids = array_filter(
|
||||||
|
array_map('intval', explode(',', (string)($settings['categories'] ?? '')))
|
||||||
|
);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$allProducts = (bool)($settings['allproducts'] ?? false);
|
||||||
|
|
||||||
|
// Extbase repositories don't work in UserFunc context — direct query.
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productQuery = $productQueryBuilder
|
||||||
|
->select('p.*')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hidden', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.legacy', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.supportproduct', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonwebsite', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonproducts', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.subproduct', 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($categoryUids) && !$allProducts) {
|
||||||
|
$productQuery
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid AND mm.tablenames = ' . $productQueryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) . ' AND mm.fieldname = ' . $productQueryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->andWhere(
|
||||||
|
$productQueryBuilder->expr()->in('mm.uid_local', $productQueryBuilder->createNamedParameter($categoryUids, Connection::PARAM_INT_ARRAY))
|
||||||
|
)
|
||||||
|
->groupBy('p.uid');
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $productQuery->executeQuery()->fetchAllAssociative();
|
||||||
|
|
||||||
|
$productsData = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productsData[] = $this->serializeProduct($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
return json_encode([
|
||||||
|
'products' => $productsData,
|
||||||
|
'debug' => [
|
||||||
|
'pageId' => (int)($GLOBALS['TSFE']->id ?? 0),
|
||||||
|
'categoryUids' => $categoryUids,
|
||||||
|
'productCount' => count($productsData),
|
||||||
|
'settings' => $settings,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($productsData);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a single product DB row to the full headless JSON structure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||||
|
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||||
|
|
||||||
|
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||||
|
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'videofile' => $this->getProductVideoFile($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.uid_local', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
|
||||||
|
$images = [];
|
||||||
|
foreach ($fileReferences as $fileRefData) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$sizes = [
|
||||||
|
'small' => ['width' => 400, 'height' => null],
|
||||||
|
'medium' => ['width' => 800, 'height' => null],
|
||||||
|
'large' => ['width' => 1200, 'height' => null],
|
||||||
|
'xlarge' => ['width' => 1600, 'height' => null],
|
||||||
|
];
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ($sizes as $sizeName => $dimensions) {
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
[
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'height' => $dimensions['height'],
|
||||||
|
'crop' => $fileRefData['crop'] ?? null
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$imageUri = $imageService->getImageUri($processedImage);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageUri,
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'descriptor' => $dimensions['width'] . 'w'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultProcessed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 800, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($defaultProcessed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type')
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRefData = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRefData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$processed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(static function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'] ?? '',
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
507
packages/vitec/Classes/UserFunc/ProductListJsonRenderer.php.bak.20260529120751
Executable file
@@ -0,0 +1,507 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use Evomedien\Vitec\Domain\Repository\ProductRepository;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render product list as JSON for headless.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (used for top-level list plugins via
|
||||||
|
* TypoScript). `renderForRecord()` processes one specific tt_content row and
|
||||||
|
* is used both internally and by ContainerChildrenProcessor to resolve a
|
||||||
|
* product-list plugin nested inside a b13 container.
|
||||||
|
*/
|
||||||
|
class ProductListJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productlist', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
// Not a product-list page: emit nothing so headless removes the key.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-list plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement tt_content row of the plugin
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Parse FlexForm of THIS element
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$categoryUids = array_filter(
|
||||||
|
array_map('intval', explode(',', (string)($settings['categories'] ?? '')))
|
||||||
|
);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$allProducts = (bool)($settings['allproducts'] ?? false);
|
||||||
|
|
||||||
|
// Extbase repositories don't work in UserFunc context — direct query.
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productQuery = $productQueryBuilder
|
||||||
|
->select('p.*')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hidden', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.legacy', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.supportproduct', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonwebsite', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.hideonproducts', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('p.subproduct', 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($categoryUids) && !$allProducts) {
|
||||||
|
$productQuery
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid AND mm.tablenames = ' . $productQueryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) . ' AND mm.fieldname = ' . $productQueryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->andWhere(
|
||||||
|
$productQueryBuilder->expr()->in('mm.uid_local', $productQueryBuilder->createNamedParameter($categoryUids, Connection::PARAM_INT_ARRAY))
|
||||||
|
)
|
||||||
|
->groupBy('p.uid');
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $productQuery->executeQuery()->fetchAllAssociative();
|
||||||
|
|
||||||
|
$productsData = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productsData[] = $this->serializeProduct($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
return json_encode([
|
||||||
|
'products' => $productsData,
|
||||||
|
'debug' => [
|
||||||
|
'pageId' => (int)($GLOBALS['TSFE']->id ?? 0),
|
||||||
|
'categoryUids' => $categoryUids,
|
||||||
|
'productCount' => count($productsData),
|
||||||
|
'settings' => $settings,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($productsData);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a single product DB row to the full headless JSON structure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'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),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'videofile' => $this->getProductVideoFile($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.uid_local', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
|
||||||
|
$images = [];
|
||||||
|
foreach ($fileReferences as $fileRefData) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$sizes = [
|
||||||
|
'small' => ['width' => 400, 'height' => null],
|
||||||
|
'medium' => ['width' => 800, 'height' => null],
|
||||||
|
'large' => ['width' => 1200, 'height' => null],
|
||||||
|
'xlarge' => ['width' => 1600, 'height' => null],
|
||||||
|
];
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ($sizes as $sizeName => $dimensions) {
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
[
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'height' => $dimensions['height'],
|
||||||
|
'crop' => $fileRefData['crop'] ?? null
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$imageUri = $imageService->getImageUri($processedImage);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageUri,
|
||||||
|
'width' => $dimensions['width'],
|
||||||
|
'descriptor' => $dimensions['width'] . 'w'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultProcessed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 800, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($defaultProcessed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type')
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRefData = $queryBuilder
|
||||||
|
->select('sfr.uid', 'sfr.title', 'sfr.description', 'sfr.alternative', 'sfr.crop')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('sfr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('sfr.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRefData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$fileRefData['uid']);
|
||||||
|
|
||||||
|
$processed = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200, 'crop' => $fileRefData['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => (int)$fileRefData['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processed),
|
||||||
|
'title' => $fileRefData['title'] ?? '',
|
||||||
|
'alternative' => $fileRefData['alternative'] ?? '',
|
||||||
|
'description' => $fileRefData['description'] ?? '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(static function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'] ?? '',
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages/vitec/Classes/UserFunc/ProductShowJsonRenderer.php
Normal file → Executable file
470
packages/vitec/Classes/UserFunc/ProductShowJsonRenderer.php.bak.20260529111828
Executable file
@@ -0,0 +1,470 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageService;
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render a single product as JSON for headless output.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (top-level plugin via TypoScript).
|
||||||
|
* `renderForRecord()` processes one specific tt_content row and is reused
|
||||||
|
* by ContainerChildrenProcessor for product-show plugins nested in a
|
||||||
|
* b13 container.
|
||||||
|
*/
|
||||||
|
class ProductShowJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productshow', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-show plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$productUid = (int)($settings['product'] ?? 0);
|
||||||
|
$layout = (int)($settings['layout'] ?? 0);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
$routeParams = $GLOBALS['TYPO3_REQUEST']->getQueryParams();
|
||||||
|
$productParam = $routeParams['tx_vitec_productshow']['product'] ?? null;
|
||||||
|
|
||||||
|
if ($productParam) {
|
||||||
|
if (!is_numeric($productParam)) {
|
||||||
|
$slugQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productBySlug = $slugQueryBuilder
|
||||||
|
->select('uid')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$slugQueryBuilder->expr()->eq('slug', $slugQueryBuilder->createNamedParameter($productParam)),
|
||||||
|
$slugQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$slugQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
$productUid = (int)($productBySlug['uid'] ?? 0);
|
||||||
|
} else {
|
||||||
|
$productUid = (int)$productParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'No product selected or found', 'debug' => ['settings' => $settings]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$product = $productQueryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$productQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'Product not found', 'debug' => ['productUid' => $productUid]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'product' => $this->serializeProduct($product),
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => [
|
||||||
|
'layout' => $layout,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = [
|
||||||
|
'pageId' => $pageId,
|
||||||
|
'productUid' => $productUid,
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => $settings,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||||
|
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||||
|
|
||||||
|
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||||
|
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($fileReferences)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$images = [];
|
||||||
|
|
||||||
|
foreach ($fileReferences as $fileRef) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => '1874c', 'height' => '625c']
|
||||||
|
);
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ([400, 800, 1200, 1600] as $width) {
|
||||||
|
$processedVariant = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => $width . 'c', 'height' => (int)($width / 3) . 'c']
|
||||||
|
);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageService->getImageUri($processedVariant),
|
||||||
|
'width' => $width,
|
||||||
|
'descriptor' => $width . 'w',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRef) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductCategories(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'],
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
514
packages/vitec/Classes/UserFunc/ProductShowJsonRenderer.php.bak.20260529115809
Executable file
@@ -0,0 +1,514 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageService;
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render a single product as JSON for headless output.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (top-level plugin via TypoScript).
|
||||||
|
* `renderForRecord()` processes one specific tt_content row and is reused
|
||||||
|
* by ContainerChildrenProcessor for product-show plugins nested in a
|
||||||
|
* b13 container.
|
||||||
|
*/
|
||||||
|
class ProductShowJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productshow', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-show plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$productUid = (int)($settings['product'] ?? 0);
|
||||||
|
$layout = (int)($settings['layout'] ?? 0);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
$routeParams = $GLOBALS['TYPO3_REQUEST']->getQueryParams();
|
||||||
|
$productParam = $routeParams['tx_vitec_productshow']['product'] ?? null;
|
||||||
|
|
||||||
|
if ($productParam) {
|
||||||
|
if (!is_numeric($productParam)) {
|
||||||
|
$slugQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productBySlug = $slugQueryBuilder
|
||||||
|
->select('uid')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$slugQueryBuilder->expr()->eq('slug', $slugQueryBuilder->createNamedParameter($productParam)),
|
||||||
|
$slugQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$slugQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
$productUid = (int)($productBySlug['uid'] ?? 0);
|
||||||
|
} else {
|
||||||
|
$productUid = (int)$productParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'No product selected or found', 'debug' => ['settings' => $settings]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$product = $productQueryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$productQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'Product not found', 'debug' => ['productUid' => $productUid]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'product' => $this->serializeProduct($product),
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => [
|
||||||
|
'layout' => $layout,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = [
|
||||||
|
'pageId' => $pageId,
|
||||||
|
'productUid' => $productUid,
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => $settings,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||||
|
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||||
|
|
||||||
|
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||||
|
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'videofile' => $this->getProductVideoFile($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($fileReferences)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$images = [];
|
||||||
|
|
||||||
|
foreach ($fileReferences as $fileRef) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => '1874c', 'height' => '625c']
|
||||||
|
);
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ([400, 800, 1200, 1600] as $width) {
|
||||||
|
$processedVariant = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => $width . 'c', 'height' => (int)($width / 3) . 'c']
|
||||||
|
);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageService->getImageUri($processedVariant),
|
||||||
|
'width' => $width,
|
||||||
|
'descriptor' => $width . 'w',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRef) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'],
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
514
packages/vitec/Classes/UserFunc/ProductShowJsonRenderer.php.bak.20260529120751
Executable file
@@ -0,0 +1,514 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
|
use TYPO3\CMS\Core\Imaging\ImageService;
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc to render a single product as JSON for headless output.
|
||||||
|
*
|
||||||
|
* `render()` performs page discovery (top-level plugin via TypoScript).
|
||||||
|
* `renderForRecord()` processes one specific tt_content row and is reused
|
||||||
|
* by ContainerChildrenProcessor for product-show plugins nested in a
|
||||||
|
* b13 container.
|
||||||
|
*/
|
||||||
|
class ProductShowJsonRenderer
|
||||||
|
{
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tt_content');
|
||||||
|
|
||||||
|
$contentElements = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('vitec_productshow', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($contentElements)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($contentElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render exactly the given tt_content row (the product-show plugin element).
|
||||||
|
* Exception-safe: returns '' on any failure.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$productUid = (int)($settings['product'] ?? 0);
|
||||||
|
$layout = (int)($settings['layout'] ?? 0);
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
$routeParams = $GLOBALS['TYPO3_REQUEST']->getQueryParams();
|
||||||
|
$productParam = $routeParams['tx_vitec_productshow']['product'] ?? null;
|
||||||
|
|
||||||
|
if ($productParam) {
|
||||||
|
if (!is_numeric($productParam)) {
|
||||||
|
$slugQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$productBySlug = $slugQueryBuilder
|
||||||
|
->select('uid')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$slugQueryBuilder->expr()->eq('slug', $slugQueryBuilder->createNamedParameter($productParam)),
|
||||||
|
$slugQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$slugQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
$productUid = (int)($productBySlug['uid'] ?? 0);
|
||||||
|
} else {
|
||||||
|
$productUid = (int)$productParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$productUid) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'No product selected or found', 'debug' => ['settings' => $settings]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$productQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$product = $productQueryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('tx_vitec_domain_model_product')
|
||||||
|
->where(
|
||||||
|
$productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$productQueryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$productQueryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return $debugMode
|
||||||
|
? json_encode(['error' => 'Product not found', 'debug' => ['productUid' => $productUid]])
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'product' => $this->serializeProduct($product),
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => [
|
||||||
|
'layout' => $layout,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = [
|
||||||
|
'pageId' => $pageId,
|
||||||
|
'productUid' => $productUid,
|
||||||
|
'layout' => $layout,
|
||||||
|
'settings' => $settings,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $product
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
protected function serializeProduct(array $product): array
|
||||||
|
{
|
||||||
|
$uid = (int)$product['uid'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
|
||||||
|
'title' => (string)($product['title'] ?? ''),
|
||||||
|
'slug' => (string)($product['slug'] ?? ''),
|
||||||
|
'urltitle' => (string)($product['urltitle'] ?? ''),
|
||||||
|
'seotitle' => (string)($product['seotitle'] ?? ''),
|
||||||
|
'seometa' => (string)($product['seometa'] ?? ''),
|
||||||
|
'keywords' => (string)($product['keywords'] ?? ''),
|
||||||
|
'structureddata' => (string)($product['structureddata'] ?? ''),
|
||||||
|
'teaser' => (string)($product['teaser'] ?? ''),
|
||||||
|
'subtitle' => (string)($product['subtitle'] ?? ''),
|
||||||
|
'video' => (string)($product['video'] ?? ''),
|
||||||
|
'applications' => (string)($product['applications'] ?? ''),
|
||||||
|
'description' => (string)($product['description'] ?? ''),
|
||||||
|
'highlights' => (string)($product['highlights'] ?? ''),
|
||||||
|
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||||
|
'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),
|
||||||
|
'hideondatasheets' => (bool)($product['hideondatasheets'] ?? false),
|
||||||
|
'hideonproducts' => (bool)($product['hideonproducts'] ?? false),
|
||||||
|
'shortcut' => (bool)($product['shortcut'] ?? false),
|
||||||
|
'legacy' => (bool)($product['legacy'] ?? false),
|
||||||
|
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||||
|
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||||
|
|
||||||
|
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||||
|
|
||||||
|
'categories' => $this->getProductCategories($uid),
|
||||||
|
'images' => $this->getProductImages($uid),
|
||||||
|
'downloads' => $this->getProductDownloads($uid),
|
||||||
|
'ogimage' => $this->getProductOgImage($uid),
|
||||||
|
'videofile' => $this->getProductVideoFile($uid),
|
||||||
|
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductImages(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileReferences = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('productimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($fileReferences)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$images = [];
|
||||||
|
|
||||||
|
foreach ($fileReferences as $fileRef) {
|
||||||
|
try {
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => '1874c', 'height' => '625c']
|
||||||
|
);
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach ([400, 800, 1200, 1600] as $width) {
|
||||||
|
$processedVariant = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => $width . 'c', 'height' => (int)($width / 3) . 'c']
|
||||||
|
);
|
||||||
|
$srcset[] = [
|
||||||
|
'url' => $imageService->getImageUri($processedVariant),
|
||||||
|
'width' => $width,
|
||||||
|
'descriptor' => $width . 'w',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$images[] = [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
protected function getProductOgImage(int $productUid): ?array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $queryBuilder
|
||||||
|
->select('*')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('ogimage', ParameterType::STRING)),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$fileRef) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject($fileRef['uid']);
|
||||||
|
$originalFile = $fileReference->getOriginalFile();
|
||||||
|
|
||||||
|
$processedImage = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 1200]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => $fileRef['uid'],
|
||||||
|
'url' => $imageService->getImageUri($processedImage),
|
||||||
|
'title' => $fileReference->getTitle() ?: '',
|
||||||
|
'alternative' => $fileReference->getAlternative() ?: '',
|
||||||
|
'description' => $fileReference->getDescription() ?: '',
|
||||||
|
'properties' => [
|
||||||
|
'width' => $originalFile->getProperty('width'),
|
||||||
|
'height' => $originalFile->getProperty('height'),
|
||||||
|
'mimeType' => $originalFile->getMimeType(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
|
||||||
|
$categories = $queryBuilder
|
||||||
|
->select('c.uid', 'c.title', 'c.description')
|
||||||
|
->from('sys_category', 'c')
|
||||||
|
->join(
|
||||||
|
'c',
|
||||||
|
'sys_category_record_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_local = c.uid AND mm.tablenames = ' .
|
||||||
|
$queryBuilder->createNamedParameter('tx_vitec_domain_model_product', ParameterType::STRING) .
|
||||||
|
' AND mm.fieldname = ' .
|
||||||
|
$queryBuilder->createNamedParameter('categories', ParameterType::STRING)
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_foreign', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('c.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('c.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
return array_map(function ($cat) {
|
||||||
|
return [
|
||||||
|
'uid' => (int)$cat['uid'],
|
||||||
|
'title' => $cat['title'],
|
||||||
|
'description' => $cat['description'] ?? '',
|
||||||
|
];
|
||||||
|
}, $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProductDownloads(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_download');
|
||||||
|
|
||||||
|
$downloads = $queryBuilder
|
||||||
|
->select('d.*')
|
||||||
|
->from('tx_vitec_domain_model_download', 'd')
|
||||||
|
->join(
|
||||||
|
'd',
|
||||||
|
'tx_vitec_product_download_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = d.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('d.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hidden', 0),
|
||||||
|
$queryBuilder->expr()->eq('d.hideonwebsite', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($downloads as $download) {
|
||||||
|
$fileInfo = null;
|
||||||
|
|
||||||
|
if (!empty($download['file'])) {
|
||||||
|
$fileQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
|
||||||
|
$fileRef = $fileQueryBuilder
|
||||||
|
->select('fr.uid', '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(
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.uid_foreign', $fileQueryBuilder->createNamedParameter((int)$download['uid'], ParameterType::INTEGER)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.tablenames', $fileQueryBuilder->createNamedParameter('tx_vitec_domain_model_download', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.fieldname', $fileQueryBuilder->createNamedParameter('file', ParameterType::STRING)),
|
||||||
|
$fileQueryBuilder->expr()->eq('fr.deleted', 0),
|
||||||
|
$fileQueryBuilder->expr()->eq('f.missing', 0)
|
||||||
|
)
|
||||||
|
->orderBy('fr.sorting_foreign', 'ASC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if ($fileRef) {
|
||||||
|
$fileInfo = [
|
||||||
|
'uid' => (int)$fileRef['file_uid'],
|
||||||
|
'name' => $fileRef['name'],
|
||||||
|
'url' => '/fileadmin' . $fileRef['identifier'],
|
||||||
|
'size' => (int)$fileRef['size'],
|
||||||
|
'extension' => $fileRef['extension'],
|
||||||
|
'mimeType' => $fileRef['mime_type'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'uid' => (int)$download['uid'],
|
||||||
|
'title' => $download['title'] ?? '',
|
||||||
|
'slug' => $download['slug'] ?? '',
|
||||||
|
'teaser' => $download['teaser'] ?? '',
|
||||||
|
'description' => $download['description'] ?? '',
|
||||||
|
'keywords' => $download['keywords'] ?? '',
|
||||||
|
'icon' => $download['icon'] ?? '',
|
||||||
|
'file' => $fileInfo,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRelatedProducts(int $productUid): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_product');
|
||||||
|
|
||||||
|
$related = $queryBuilder
|
||||||
|
->select('p.uid', 'p.title', 'p.slug', 'p.subtitle', 'p.teaser', 'p.description')
|
||||||
|
->from('tx_vitec_domain_model_product', 'p')
|
||||||
|
->join(
|
||||||
|
'p',
|
||||||
|
'tx_vitec_product_related_mm',
|
||||||
|
'mm',
|
||||||
|
'mm.uid_foreign = p.uid'
|
||||||
|
)
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('mm.uid_local', $queryBuilder->createNamedParameter($productUid, ParameterType::INTEGER)),
|
||||||
|
$queryBuilder->expr()->eq('p.deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('p.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('mm.sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($related as $rel) {
|
||||||
|
$relUid = (int)$rel['uid'];
|
||||||
|
$result[] = [
|
||||||
|
'uid' => $relUid,
|
||||||
|
'title' => (string)($rel['title'] ?? ''),
|
||||||
|
'slug' => (string)($rel['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($rel['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($rel['teaser'] ?? ''),
|
||||||
|
'description' => (string)($rel['description'] ?? ''),
|
||||||
|
'link' => '/product/' . (string)($rel['slug'] ?? ''),
|
||||||
|
'images' => $this->getProductImages($relUid),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages/vitec/Classes/UserFunc/UsecaseListJsonRenderer.php
Normal file → Executable file
0
packages/vitec/Classes/UserFunc/UsecaseShowJsonRenderer.php
Normal file → Executable file
0
packages/vitec/Classes/View/BackendLayoutDataProvider.php
Normal file → Executable file
0
packages/vitec/Classes/View/VitecBackendLayoutView.php
Normal file → Executable file
0
packages/vitec/Configuration/FlexForms/Container.xml
Normal file → Executable file
0
packages/vitec/Configuration/Icons.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/pages.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_25_25_25_25.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_33_33_33.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_33_66.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_50_50.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_66_33.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_container.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_shared.php
Normal file → Executable file
0
packages/vitec/Configuration/TCA/tx_vitec_domain_model_product.php
Normal file → Executable file
@@ -0,0 +1,541 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'ctrl' => [
|
||||||
|
'title' => 'VITEC Product',
|
||||||
|
'label' => 'title',
|
||||||
|
'tstamp' => 'tstamp',
|
||||||
|
'crdate' => 'crdate',
|
||||||
|
'cruser_id' => 'cruser_id',
|
||||||
|
'versioningWS' => true,
|
||||||
|
'languageField' => 'sys_language_uid',
|
||||||
|
'transOrigPointerField' => 'l10n_parent',
|
||||||
|
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||||
|
'delete' => 'deleted',
|
||||||
|
'enablecolumns' => [
|
||||||
|
'disabled' => 'hidden',
|
||||||
|
'starttime' => 'starttime',
|
||||||
|
'endtime' => 'endtime',
|
||||||
|
],
|
||||||
|
'searchFields' => 'title,slug',
|
||||||
|
'iconfile' => 'EXT:vitec/Resources/Public/Icons/tx_vitec_domain_model_product.gif',
|
||||||
|
'security' => [
|
||||||
|
'ignorePageTypeRestriction' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'types' => [
|
||||||
|
'1' => ['showitem' => 'title, subtitle, slug, teaser, description, applications, highlights, contentelement, contentelementcta, downloads,
|
||||||
|
--div--;SEO, seotitle, urltitle, seometa, keywords, structureddata,
|
||||||
|
--div--;Images and Videos, productimage, ogimage, video,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories, categories,
|
||||||
|
--div--;Visibility, hideonapp, hideonwebsite, hideondatasheets, hideonproducts, shortcut, shortcutpid,
|
||||||
|
--div--;Misc, legacy, supportproduct, subproduct, relatedprodukt,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden, starttime, endtime'],
|
||||||
|
],
|
||||||
|
'columns' => [
|
||||||
|
'sys_language_uid' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'language',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'l10n_parent' => [
|
||||||
|
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectSingle',
|
||||||
|
'default' => 0,
|
||||||
|
'items' => [
|
||||||
|
['', 0],
|
||||||
|
],
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_product',
|
||||||
|
'foreign_table_where' => 'AND {#tx_vitec_domain_model_product}.{#pid}=###CURRENT_PID### AND {#tx_vitec_domain_model_product}.{#sys_language_uid} IN (-1,0)',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'l10n_diffsource' => [
|
||||||
|
'config' => [
|
||||||
|
'type' => 'passthrough',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hidden' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'starttime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputDateTime',
|
||||||
|
'eval' => 'datetime,int',
|
||||||
|
'default' => 0,
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'endtime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputDateTime',
|
||||||
|
'eval' => 'datetime,int',
|
||||||
|
'default' => 0,
|
||||||
|
'range' => [
|
||||||
|
'upper' => mktime(0, 0, 0, 1, 1, 2038)
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'categories' => [
|
||||||
|
'config' => [
|
||||||
|
'type' => 'category'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'title' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.title',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.title.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'required' => true,
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'slug' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.slug',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.slug.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'slug',
|
||||||
|
'size' => 50,
|
||||||
|
'generatorOptions' => [
|
||||||
|
'fields' => ['title'], // TODO: adjust this field to the one you want to use
|
||||||
|
'fieldSeparator' => '-',
|
||||||
|
'replacements' => [
|
||||||
|
'/' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'fallbackCharacter' => '-',
|
||||||
|
'eval' => 'uniqueInPid',
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
'seotitle' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'SEO-Title',
|
||||||
|
'description' => 'SEO specific title, used for sharing options',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'urltitle' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'URL-Title',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.urltitle.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'video' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'Product Video - just the Youtube Clip ID',
|
||||||
|
'description' => 'Product Video - just the Youtube Clip ID',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'downloads' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Downloads',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectMultipleSideBySide',
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_download',
|
||||||
|
'MM' => 'tx_vitec_product_download_mm', // Define the MM table for the relation
|
||||||
|
'size' => 10,
|
||||||
|
'maxitems' => 9999,
|
||||||
|
'minitems' => 0,
|
||||||
|
'enableMultiSelectFilterTextfield' => true, // Optional: Adds a search box for filtering
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'structureddata' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Structured Data in JSON Format',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'keywords' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Keywords',
|
||||||
|
'description' => 'Keywords for SEO, separated by commas',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'seometa' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'SEO Meta Description',
|
||||||
|
'description' => 'SEO specific meta description, used for sharing options',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'teaser' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Short Teaser (optional)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'subtitle' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Subtitle',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hideonapp' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on App',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hideonwebsite' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Website',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'hideonproducts' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Product Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'hideondatasheets' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Datasheets Page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'applications' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Applications',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
'description' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
|
||||||
|
'highlights' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Highlights',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
|
||||||
|
'shortcut' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Does this Product have a custom Page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'shortcutpid' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'Page ID',
|
||||||
|
'description' => 'PID of the custom page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'legacy' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Is this a legacy produc?',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'supportproduct' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Is this a support product?',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'subproduct' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Product is a sub-products',
|
||||||
|
'description' => 'This Product will not be shown as a main product',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'relatedprodukt' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Related Products',
|
||||||
|
'description' => 'Select related products for this product',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectMultipleSideBySide',
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_product', // Reference the same table
|
||||||
|
'MM' => 'tx_vitec_product_related_mm', // Define the MM table for the relation
|
||||||
|
'size' => 10,
|
||||||
|
'maxitems' => 9999,
|
||||||
|
'minitems' => 0,
|
||||||
|
'enableMultiSelectFilterTextfield' => true, // Optional: Adds a search box for filtering
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'productimage' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Product Image(s)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'inline',
|
||||||
|
'foreign_table' => 'sys_file_reference',
|
||||||
|
'foreign_field' => 'uid_foreign',
|
||||||
|
'foreign_sortby' => 'sorting_foreign',
|
||||||
|
'foreign_table_field' => 'tablenames',
|
||||||
|
'foreign_match_fields' => [
|
||||||
|
'fieldname' => 'productimage',
|
||||||
|
],
|
||||||
|
'appearance' => [
|
||||||
|
'collapseAll' => true,
|
||||||
|
'levelLinksPosition' => 'top',
|
||||||
|
'showSynchronizationLink' => true,
|
||||||
|
'showPossibleLocalizationRecords' => true,
|
||||||
|
'showAllLocalizationLink' => true,
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true,
|
||||||
|
],
|
||||||
|
'filter' => [
|
||||||
|
[
|
||||||
|
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||||
|
'parameters' => [
|
||||||
|
'allowedFileExtensions' => 'jpg,jpeg,png,gif',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'maxitems' => 10,
|
||||||
|
'minitems' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'ogimage' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Open Graph Image',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'inline',
|
||||||
|
'foreign_table' => 'sys_file_reference',
|
||||||
|
'foreign_field' => 'uid_foreign',
|
||||||
|
'foreign_sortby' => 'sorting_foreign',
|
||||||
|
'foreign_table_field' => 'tablenames',
|
||||||
|
'foreign_match_fields' => [
|
||||||
|
'fieldname' => 'ogimage',
|
||||||
|
],
|
||||||
|
'appearance' => [
|
||||||
|
'collapseAll' => true,
|
||||||
|
'levelLinksPosition' => 'top',
|
||||||
|
'showSynchronizationLink' => true,
|
||||||
|
'showPossibleLocalizationRecords' => true,
|
||||||
|
'showAllLocalizationLink' => true,
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true,
|
||||||
|
],
|
||||||
|
'filter' => [
|
||||||
|
[
|
||||||
|
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||||
|
'parameters' => [
|
||||||
|
'allowedFileExtensions' => 'jpg,jpeg,png,gif,webp',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'maxitems' => 1, // Allow only one image
|
||||||
|
'minitems' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'contentelement' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Select Content Element for Key Features Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputLink',
|
||||||
|
'softref' => 'typolink',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'fieldControl' => [
|
||||||
|
'linkPopup' => [
|
||||||
|
'options' => [
|
||||||
|
'title' => 'Select Content Element',
|
||||||
|
'blindLinkOptions' => 'mail,folder,url', // Disable unnecessary link types
|
||||||
|
'blindLinkFields' => 'class,params', // Disable unnecessary fields
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'contentelementcta' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Select Content Element for CTA Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputLink',
|
||||||
|
'softref' => 'typolink',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'fieldControl' => [
|
||||||
|
'linkPopup' => [
|
||||||
|
'options' => [
|
||||||
|
'title' => 'Select Content Element',
|
||||||
|
'blindLinkOptions' => 'mail,folder,url', // Disable unnecessary link types
|
||||||
|
'blindLinkFields' => 'class,params', // Disable unnecessary fields
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -0,0 +1,576 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'ctrl' => [
|
||||||
|
'title' => 'VITEC Product',
|
||||||
|
'label' => 'title',
|
||||||
|
'tstamp' => 'tstamp',
|
||||||
|
'crdate' => 'crdate',
|
||||||
|
'cruser_id' => 'cruser_id',
|
||||||
|
'versioningWS' => true,
|
||||||
|
'languageField' => 'sys_language_uid',
|
||||||
|
'transOrigPointerField' => 'l10n_parent',
|
||||||
|
'transOrigDiffSourceField' => 'l10n_diffsource',
|
||||||
|
'delete' => 'deleted',
|
||||||
|
'enablecolumns' => [
|
||||||
|
'disabled' => 'hidden',
|
||||||
|
'starttime' => 'starttime',
|
||||||
|
'endtime' => 'endtime',
|
||||||
|
],
|
||||||
|
'searchFields' => 'title,slug',
|
||||||
|
'iconfile' => 'EXT:vitec/Resources/Public/Icons/tx_vitec_domain_model_product.gif',
|
||||||
|
'security' => [
|
||||||
|
'ignorePageTypeRestriction' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'types' => [
|
||||||
|
'1' => ['showitem' => 'title, subtitle, slug, teaser, description, applications, highlights, contentelement, contentelementcta, downloads,
|
||||||
|
--div--;SEO, seotitle, urltitle, seometa, keywords, structureddata,
|
||||||
|
--div--;Images and Videos, productimage, ogimage, video, videofile,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories, categories,
|
||||||
|
--div--;Visibility, hideonapp, hideonwebsite, hideondatasheets, hideonproducts, shortcut, shortcutpid,
|
||||||
|
--div--;Misc, legacy, supportproduct, subproduct, relatedprodukt,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden, starttime, endtime'],
|
||||||
|
],
|
||||||
|
'columns' => [
|
||||||
|
'sys_language_uid' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'language',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'l10n_parent' => [
|
||||||
|
'displayCond' => 'FIELD:sys_language_uid:>:0',
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectSingle',
|
||||||
|
'default' => 0,
|
||||||
|
'items' => [
|
||||||
|
['', 0],
|
||||||
|
],
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_product',
|
||||||
|
'foreign_table_where' => 'AND {#tx_vitec_domain_model_product}.{#pid}=###CURRENT_PID### AND {#tx_vitec_domain_model_product}.{#sys_language_uid} IN (-1,0)',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'l10n_diffsource' => [
|
||||||
|
'config' => [
|
||||||
|
'type' => 'passthrough',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hidden' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'starttime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputDateTime',
|
||||||
|
'eval' => 'datetime,int',
|
||||||
|
'default' => 0,
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'endtime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputDateTime',
|
||||||
|
'eval' => 'datetime,int',
|
||||||
|
'default' => 0,
|
||||||
|
'range' => [
|
||||||
|
'upper' => mktime(0, 0, 0, 1, 1, 2038)
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'categories' => [
|
||||||
|
'config' => [
|
||||||
|
'type' => 'category'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'title' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.title',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.title.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'required' => true,
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'slug' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.slug',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.slug.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'slug',
|
||||||
|
'size' => 50,
|
||||||
|
'generatorOptions' => [
|
||||||
|
'fields' => ['title'], // TODO: adjust this field to the one you want to use
|
||||||
|
'fieldSeparator' => '-',
|
||||||
|
'replacements' => [
|
||||||
|
'/' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'fallbackCharacter' => '-',
|
||||||
|
'eval' => 'uniqueInPid',
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
'seotitle' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'SEO-Title',
|
||||||
|
'description' => 'SEO specific title, used for sharing options',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'urltitle' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'URL-Title',
|
||||||
|
'description' => 'LLL:EXT:vitec/Resources/Private/Language/locallang_db.xlf:tx_vitec_domain_model_product.urltitle.description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'video' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'Product Video - just the Youtube Clip ID',
|
||||||
|
'description' => 'Product Video - just the Youtube Clip ID',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'downloads' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Downloads',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectMultipleSideBySide',
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_download',
|
||||||
|
'MM' => 'tx_vitec_product_download_mm', // Define the MM table for the relation
|
||||||
|
'size' => 10,
|
||||||
|
'maxitems' => 9999,
|
||||||
|
'minitems' => 0,
|
||||||
|
'enableMultiSelectFilterTextfield' => true, // Optional: Adds a search box for filtering
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'structureddata' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Structured Data in JSON Format',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'keywords' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Keywords',
|
||||||
|
'description' => 'Keywords for SEO, separated by commas',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'seometa' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'SEO Meta Description',
|
||||||
|
'description' => 'SEO specific meta description, used for sharing options',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'cols' => 40,
|
||||||
|
'rows' => 15,
|
||||||
|
'eval' => 'trim'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'teaser' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Short Teaser (optional)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'subtitle' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Subtitle',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hideonapp' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on App',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'hideonwebsite' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Website',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'hideonproducts' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Product Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'hideondatasheets' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'If checked - Product will not be shown on Datasheets Page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'applications' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Applications',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
'description' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Description',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
|
||||||
|
'highlights' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Highlights',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'enableRichtext' => 'true',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
'defaultExtras' => 'richtext:rte_transform[mode=ts_css]'
|
||||||
|
],
|
||||||
|
|
||||||
|
'shortcut' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Does this Product have a custom Page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'shortcutpid' => [
|
||||||
|
'exclude' => false,
|
||||||
|
'label' => 'Page ID',
|
||||||
|
'description' => 'PID of the custom page',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 30,
|
||||||
|
'eval' => 'trim',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'legacy' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Is this a legacy produc?',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'supportproduct' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Is this a support product?',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'subproduct' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Product is a sub-products',
|
||||||
|
'description' => 'This Product will not be shown as a main product',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
0 => '',
|
||||||
|
1 => '',
|
||||||
|
'invertStateDisplay' => false
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'relatedprodukt' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Related Products',
|
||||||
|
'description' => 'Select related products for this product',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectMultipleSideBySide',
|
||||||
|
'foreign_table' => 'tx_vitec_domain_model_product', // Reference the same table
|
||||||
|
'MM' => 'tx_vitec_product_related_mm', // Define the MM table for the relation
|
||||||
|
'size' => 10,
|
||||||
|
'maxitems' => 9999,
|
||||||
|
'minitems' => 0,
|
||||||
|
'enableMultiSelectFilterTextfield' => true, // Optional: Adds a search box for filtering
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'productimage' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Product Image(s)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'inline',
|
||||||
|
'foreign_table' => 'sys_file_reference',
|
||||||
|
'foreign_field' => 'uid_foreign',
|
||||||
|
'foreign_sortby' => 'sorting_foreign',
|
||||||
|
'foreign_table_field' => 'tablenames',
|
||||||
|
'foreign_match_fields' => [
|
||||||
|
'fieldname' => 'productimage',
|
||||||
|
],
|
||||||
|
'appearance' => [
|
||||||
|
'collapseAll' => true,
|
||||||
|
'levelLinksPosition' => 'top',
|
||||||
|
'showSynchronizationLink' => true,
|
||||||
|
'showPossibleLocalizationRecords' => true,
|
||||||
|
'showAllLocalizationLink' => true,
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true,
|
||||||
|
],
|
||||||
|
'filter' => [
|
||||||
|
[
|
||||||
|
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||||
|
'parameters' => [
|
||||||
|
'allowedFileExtensions' => 'jpg,jpeg,png,gif',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'maxitems' => 10,
|
||||||
|
'minitems' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'ogimage' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Open Graph Image',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'inline',
|
||||||
|
'foreign_table' => 'sys_file_reference',
|
||||||
|
'foreign_field' => 'uid_foreign',
|
||||||
|
'foreign_sortby' => 'sorting_foreign',
|
||||||
|
'foreign_table_field' => 'tablenames',
|
||||||
|
'foreign_match_fields' => [
|
||||||
|
'fieldname' => 'ogimage',
|
||||||
|
],
|
||||||
|
'appearance' => [
|
||||||
|
'collapseAll' => true,
|
||||||
|
'levelLinksPosition' => 'top',
|
||||||
|
'showSynchronizationLink' => true,
|
||||||
|
'showPossibleLocalizationRecords' => true,
|
||||||
|
'showAllLocalizationLink' => true,
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true,
|
||||||
|
],
|
||||||
|
'filter' => [
|
||||||
|
[
|
||||||
|
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||||
|
'parameters' => [
|
||||||
|
'allowedFileExtensions' => 'jpg,jpeg,png,gif,webp',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'maxitems' => 1, // Allow only one image
|
||||||
|
'minitems' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'videofile' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Video File (Upload or Local)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'inline',
|
||||||
|
'foreign_table' => 'sys_file_reference',
|
||||||
|
'foreign_field' => 'uid_foreign',
|
||||||
|
'foreign_sortby' => 'sorting_foreign',
|
||||||
|
'foreign_table_field' => 'tablenames',
|
||||||
|
'foreign_match_fields' => [
|
||||||
|
'fieldname' => 'videofile',
|
||||||
|
],
|
||||||
|
'appearance' => [
|
||||||
|
'collapseAll' => true,
|
||||||
|
'levelLinksPosition' => 'top',
|
||||||
|
'showSynchronizationLink' => true,
|
||||||
|
'showPossibleLocalizationRecords' => true,
|
||||||
|
'showAllLocalizationLink' => true,
|
||||||
|
],
|
||||||
|
'behaviour' => [
|
||||||
|
'allowLanguageSynchronization' => true,
|
||||||
|
],
|
||||||
|
'filter' => [
|
||||||
|
[
|
||||||
|
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||||
|
'parameters' => [
|
||||||
|
'allowedFileExtensions' => 'mp4,webm,ogv,mov,m4v',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'maxitems' => 1,
|
||||||
|
'minitems' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'contentelement' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Select Content Element for Key Features Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputLink',
|
||||||
|
'softref' => 'typolink',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'fieldControl' => [
|
||||||
|
'linkPopup' => [
|
||||||
|
'options' => [
|
||||||
|
'title' => 'Select Content Element',
|
||||||
|
'blindLinkOptions' => 'mail,folder,url', // Disable unnecessary link types
|
||||||
|
'blindLinkFields' => 'class,params', // Disable unnecessary fields
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'contentelementcta' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'Select Content Element for CTA Section',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'renderType' => 'inputLink',
|
||||||
|
'softref' => 'typolink',
|
||||||
|
'eval' => 'trim',
|
||||||
|
'fieldControl' => [
|
||||||
|
'linkPopup' => [
|
||||||
|
'options' => [
|
||||||
|
'title' => 'Select Content Element',
|
||||||
|
'blindLinkOptions' => 'mail,folder,url', // Disable unnecessary link types
|
||||||
|
'blindLinkFields' => 'class,params', // Disable unnecessary fields
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
],
|
||||||
|
];
|
||||||
0
packages/vitec/Configuration/TypoScript/Headless/vitec_containers.typoscript
Normal file → Executable file
0
packages/vitec/Configuration/TypoScript/Headless/vitec_menus.typoscript
Normal file → Executable file
0
packages/vitec/Resources/Private/Language/locallang_containers.xlf
Normal file → Executable file
0
packages/vitec/Resources/Private/Language/locallang_pages.xlf
Normal file → Executable file
0
packages/vitec/Resources/Public/Icons/vitec-cols-25-25-25-25.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-33-33-33.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-33-66.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-50-50.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-66-33.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 202 B |
0
packages/vitec/Resources/Public/Icons/vitec-container.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 447 B |
0
packages/vitec/ext_localconf.php
Normal file → Executable file
0
packages/vitec/ext_tables.sql
Normal file → Executable file
171
packages/vitec/ext_tables.sql.bak.20260529111828
Executable file
@@ -0,0 +1,171 @@
|
|||||||
|
CREATE TABLE tx_vitec_domain_model_product (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
urltitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
seotitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
seometa text,
|
||||||
|
keywords text,
|
||||||
|
productimage int(11) DEFAULT '0' NOT NULL,
|
||||||
|
structureddata text,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
applications text,
|
||||||
|
highlights text,
|
||||||
|
description text,
|
||||||
|
image INTEGER,
|
||||||
|
relatedimage INTEGER,
|
||||||
|
ogimage INTEGER,
|
||||||
|
legacy tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
supportproduct tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
subproduct tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
cta varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
sorting1 smallint(5) NOT NULL,
|
||||||
|
sorting2 smallint(5) NOT NULL,
|
||||||
|
sorting3 smallint(5) NOT NULL,
|
||||||
|
sorting4 smallint(5) NOT NULL,
|
||||||
|
sorting5 smallint(5) NOT NULL,
|
||||||
|
links text,
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideondatasheets smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonproducts smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
shortcut tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
shortcutpid smallint(5) NOT NULL,
|
||||||
|
video varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key1 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key2 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key3 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext1 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext2 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext3 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
productlayout int(11) DEFAULT '0' NOT NULL,
|
||||||
|
contentelement varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
contentelementcta varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
KEY parent (pid)
|
||||||
|
);
|
||||||
|
CREATE TABLE tx_vitec_domain_model_download (
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) NOT NULL DEFAULT '',
|
||||||
|
keywords varchar(255) NOT NULL DEFAULT '',
|
||||||
|
description text,
|
||||||
|
file int(11) unsigned NOT NULL DEFAULT '0',
|
||||||
|
sort1 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
sort2 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
sort3 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
private_download smallint(1) unsigned NOT NULL DEFAULT '0',
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideondatasheets smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonproducts smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
icon varchar(255) NOT NULL DEFAULT '',
|
||||||
|
filepath varchar(255) NOT NULL DEFAULT '',
|
||||||
|
fileprefix varchar(255) NOT NULL DEFAULT '',
|
||||||
|
useolddl smallint(1) unsigned NOT NULL DEFAULT '0'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_product_download_mm (
|
||||||
|
uid_local int(11) DEFAULT '0' NOT NULL,
|
||||||
|
uid_foreign int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sorting int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sorting_foreign int(11) DEFAULT '0' NOT NULL,
|
||||||
|
KEY uid_local (uid_local),
|
||||||
|
KEY uid_foreign (uid_foreign)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_product_related_mm (
|
||||||
|
uid_local INT(11) NOT NULL,
|
||||||
|
uid_foreign INT(11) NOT NULL,
|
||||||
|
sorting INT(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid_local, uid_foreign)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_usecase (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
caseimage INTEGER,
|
||||||
|
logoimage INTEGER,
|
||||||
|
singlepid varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_solution (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sys_language_uid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_parent int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_diffsource mediumblob,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
image int(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid),
|
||||||
|
KEY language (l10n_parent, sys_language_uid)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_market (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sys_language_uid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_parent int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_diffsource mediumblob,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
image int(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid),
|
||||||
|
KEY language (l10n_parent, sys_language_uid)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE sys_category
|
||||||
|
ADD class VARCHAR(255) DEFAULT '' NOT NULL,
|
||||||
|
ADD filetype VARCHAR(255) DEFAULT '' NOT NULL,
|
||||||
|
ADD type VARCHAR(255) DEFAULT '' NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE tt_content (
|
||||||
|
tx_vitec_bg_variant VARCHAR(20) DEFAULT 'none' NOT NULL
|
||||||
|
);
|
||||||
172
packages/vitec/ext_tables.sql.bak.20260529120751
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
CREATE TABLE tx_vitec_domain_model_product (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
urltitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
seotitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
seometa text,
|
||||||
|
keywords text,
|
||||||
|
productimage int(11) DEFAULT '0' NOT NULL,
|
||||||
|
structureddata text,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
applications text,
|
||||||
|
highlights text,
|
||||||
|
description text,
|
||||||
|
image INTEGER,
|
||||||
|
relatedimage INTEGER,
|
||||||
|
ogimage INTEGER,
|
||||||
|
legacy tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
supportproduct tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
subproduct tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
cta varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
sorting1 smallint(5) NOT NULL,
|
||||||
|
sorting2 smallint(5) NOT NULL,
|
||||||
|
sorting3 smallint(5) NOT NULL,
|
||||||
|
sorting4 smallint(5) NOT NULL,
|
||||||
|
sorting5 smallint(5) NOT NULL,
|
||||||
|
links text,
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideondatasheets smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonproducts smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
shortcut tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
shortcutpid smallint(5) NOT NULL,
|
||||||
|
video varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key1 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key2 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
key3 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext1 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext2 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
apptext3 varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
productlayout int(11) DEFAULT '0' NOT NULL,
|
||||||
|
contentelement varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
contentelementcta varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
videofile int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
KEY parent (pid)
|
||||||
|
);
|
||||||
|
CREATE TABLE tx_vitec_domain_model_download (
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) NOT NULL DEFAULT '',
|
||||||
|
keywords varchar(255) NOT NULL DEFAULT '',
|
||||||
|
description text,
|
||||||
|
file int(11) unsigned NOT NULL DEFAULT '0',
|
||||||
|
sort1 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
sort2 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
sort3 varchar(255) NOT NULL DEFAULT '',
|
||||||
|
private_download smallint(1) unsigned NOT NULL DEFAULT '0',
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideondatasheets smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonproducts smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
icon varchar(255) NOT NULL DEFAULT '',
|
||||||
|
filepath varchar(255) NOT NULL DEFAULT '',
|
||||||
|
fileprefix varchar(255) NOT NULL DEFAULT '',
|
||||||
|
useolddl smallint(1) unsigned NOT NULL DEFAULT '0'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_product_download_mm (
|
||||||
|
uid_local int(11) DEFAULT '0' NOT NULL,
|
||||||
|
uid_foreign int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sorting int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sorting_foreign int(11) DEFAULT '0' NOT NULL,
|
||||||
|
KEY uid_local (uid_local),
|
||||||
|
KEY uid_foreign (uid_foreign)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_product_related_mm (
|
||||||
|
uid_local INT(11) NOT NULL,
|
||||||
|
uid_foreign INT(11) NOT NULL,
|
||||||
|
sorting INT(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid_local, uid_foreign)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_usecase (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
caseimage INTEGER,
|
||||||
|
logoimage INTEGER,
|
||||||
|
singlepid varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
hideonapp smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
hideonwebsite smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_solution (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sys_language_uid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_parent int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_diffsource mediumblob,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
image int(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid),
|
||||||
|
KEY language (l10n_parent, sys_language_uid)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_market (
|
||||||
|
uid int(11) NOT NULL auto_increment,
|
||||||
|
pid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
tstamp int(11) DEFAULT '0' NOT NULL,
|
||||||
|
crdate int(11) DEFAULT '0' NOT NULL,
|
||||||
|
cruser_id int(11) DEFAULT '0' NOT NULL,
|
||||||
|
deleted tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
hidden tinyint(4) DEFAULT '0' NOT NULL,
|
||||||
|
starttime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
endtime int(11) DEFAULT '0' NOT NULL,
|
||||||
|
sys_language_uid int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_parent int(11) DEFAULT '0' NOT NULL,
|
||||||
|
l10n_diffsource mediumblob,
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
subtitle varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
teaser varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
description text,
|
||||||
|
image int(11) DEFAULT '0' NOT NULL,
|
||||||
|
PRIMARY KEY (uid),
|
||||||
|
KEY parent (pid),
|
||||||
|
KEY language (l10n_parent, sys_language_uid)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE sys_category
|
||||||
|
ADD class VARCHAR(255) DEFAULT '' NOT NULL,
|
||||||
|
ADD filetype VARCHAR(255) DEFAULT '' NOT NULL,
|
||||||
|
ADD type VARCHAR(255) DEFAULT '' NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE tt_content (
|
||||||
|
tx_vitec_bg_variant VARCHAR(20) DEFAULT 'none' NOT NULL
|
||||||
|
);
|
||||||