Files
kupshop/bundles/KupShop/ContentBundle/Util/SliderUtil.php
2025-08-02 16:30:27 +02:00

349 lines
11 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\ContentBundle\Util;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Types\Type;
use KupShop\ContentBundle\Entity\Slider;
use KupShop\I18nBundle\Translations\PhotosTranslation;
use KupShop\I18nBundle\Translations\SlidersImagesTranslation;
use KupShop\I18nBundle\Translations\SlidersTranslation;
use KupShop\KupShopBundle\Util\Entity\EntityUtil;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Util\System\PathFinder;
use Query\Operator;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerException;
class SliderUtil
{
private EntityUtil $entityUtil;
private ImageLocator $imageLocator;
private PathFinder $pathFinder;
public function __construct(EntityUtil $entityUtil, ImageLocator $imageLocator, PathFinder $pathFinder)
{
$this->entityUtil = $entityUtil;
$this->imageLocator = $imageLocator;
$this->pathFinder = $pathFinder;
}
public function get(int $id, bool $random = false): ?Slider
{
$sliders = $this->fetchSliders(
Operator::andX(
Operator::equals(['sl.id' => $id]),
static::specRandomSlider($random),
),
);
return count($sliders) > 0 ? array_values($sliders)[0] : null;
}
public function getByName(string $name, bool $random = false): ?Slider
{
$sliders = $this->fetchSliders(
Operator::andX(
Operator::like(['sl.name' => $name]),
static::specRandomSlider($random),
),
);
return count($sliders) > 0 ? array_values($sliders)[0] : null;
}
/**
* @return Slider[]
*
* @throws DBALException|SerializerException
*/
public function fetchSliders(?callable $spec = null, string $indexBy = 'id'): array
{
$qb = $this->createQueryBuilder();
if ($spec) {
$qb->andWhere($spec);
}
$slidersData = [];
foreach ($qb->execute() as $item) {
$index = $item[$indexBy];
if (!isset($slidersData[$index])) {
$slidersData[$index] = [
'id' => (int) $item['id'],
'name' => $item['name'],
'custom_data' => array_replace_recursive(
json_decode($item['slider_data'] ?: '', true) ?: [],
json_decode($item['slider_data2'] ?: '', true) ?: [],
),
'images' => [],
'_index' => $index,
];
if (!empty($item['id_section'])) {
$slidersData[$index]['id_section'] = $item['id_section'];
}
}
if (isset($item['id_photo'])) {
if ($item['figure'] === 'N') {
continue;
}
$photo = $this->imageLocator->getImage(
$this->getImageArrayFromItem($item),
);
$slidersData[$index]['images'][] = [
'id' => $item['id_slider_image'],
'link' => $item['link'],
'description' => $item['description'],
'image' => '/'.$this->pathFinder->dataPath('photos/'.$photo->getSource().$photo->getImageDesktop()),
'image_data' => json_decode($item['custom_data'] ?? '', true),
'photo' => $photo,
'custom_data' => array_replace_recursive(
json_decode($item['image_data'] ?: '', true) ?: [],
json_decode($item['image_data2'] ?: '', true) ?: [],
),
];
}
}
$sliders = [];
foreach ($slidersData as $index => $sliderData) {
$sliders[$index] = $slider = $this->entityUtil->createEntity($sliderData, Slider::class);
foreach ($slider->images as &$image) {
$image['slider'] = $slider;
}
}
return $sliders;
}
public function createQueryBuilder(): QueryBuilder
{
$qb = sqlQueryBuilder()
->from('sliders', 'sl');
foreach ($this->getSelectFields() as $alias => $column) {
$qb->addSelect("{$column} as {$alias}");
}
$qb->leftJoin('sl', 'sliders_images', 'si', 'si.id_slider=sl.id AND ((si.date_from < NOW() OR si.date_from IS NULL) AND (si.date_to > NOW() OR si.date_to IS NULL))')
->join('si', 'photos', 'ph', 'ph.id = si.id_photo')
->andWhere(Translation::coalesceTranslatedFields(SlidersTranslation::class, ['name' => 'name', 'data' => 'slider_data2']))
->andWhere(
Translation::coalesceTranslatedFields(
SlidersImagesTranslation::class,
[
'description' => 'description',
'link' => 'link',
'data' => 'image_data2',
'figure' => 'figure',
]
)
)
->andWhere(
Translation::coalesceTranslatedFields(
PhotosTranslation::class,
[
'descr' => 'photo_descr',
'image_2' => 'photo_image_2',
'image_tablet' => 'photo_image_tablet',
'image_mobile' => 'photo_image_mobile',
]
)
);
if (findModule(\Modules::VIDEOS)) {
$qb->leftJoin('ph', 'videos', 'v', 'v.id_photo = ph.id');
}
return $qb;
}
protected function getSelectFields(): array
{
$fields = [
'id' => 'sl.id',
'name' => 'sl.name',
'slider_data' => 'sl.data',
'link' => 'si.link',
'description' => 'si.description',
'id_slider_image' => 'si.id',
'id_photo' => 'si.id_photo',
'image_data' => 'si.data',
'photo_id' => 'ph.id',
'photo_filename' => 'ph.filename',
'photo_descr' => 'ph.descr',
'photo_source' => 'ph.source',
'photo_image_2' => 'ph.image_2',
'photo_image_tablet' => 'ph.image_tablet',
'photo_image_mobile' => 'ph.image_mobile',
'photo_date' => 'ph.date',
'photo_sync_id' => 'ph.sync_id',
'photo_date_update' => 'ph.date_update',
'custom_data' => 'ph.data',
];
if (findModule(\Modules::VIDEOS)) {
$fields['id_video'] = 'v.id_cdn';
}
return $fields;
}
private function getImageArrayFromItem(array $item): array
{
$image = [];
foreach ($item as $key => $value) {
if (StringUtil::startsWith($key, 'photo_') || $key == 'id_video') {
$image[ltrim($key, 'photo_')] = $value;
}
}
return $image;
}
/**
* @param array{position: string, id_section: int, id_slider: int} $positionsInSections
*
* @throws DBALException
*/
public function saveSliderPositions(array $positionsInSections, ?array $onDuplicateKeyUpdate = null): void
{
if (empty($positionsInSections)) {
return;
}
$validPositions = static::getPositions();
$types = [
'id_section' => Type::INTEGER,
'id_slider' => Type::INTEGER,
'position' => Type::STRING,
];
$qb = sqlQueryBuilder()->insert('sliders_in_sections');
foreach ($positionsInSections as $mapping) {
ksort($mapping);
if (!in_array($mapping['position'], array_keys($validPositions))) {
throw new \InvalidArgumentException("Invalid position '{$mapping['position']}'");
}
$qb->multiDirectValues($mapping, $types);
}
if ($onDuplicateKeyUpdate) {
$qb->onDuplicateKeyUpdate($onDuplicateKeyUpdate);
}
$qb->execute();
}
/**
* @throws DBALException|\InvalidArgumentException
*/
public function clearSliderSections(?int $idSlider = null, ?int $idSection = null): void
{
if (!isset($idSlider) && !isset($idSection)) {
throw new \InvalidArgumentException('Both $idSlider and $idSection cannot be empty');
}
$qb = sqlQueryBuilder()->delete('sliders_in_sections');
if (isset($idSlider)) {
$qb->andWhere(Operator::equals(['id_slider' => $idSlider]));
}
if (isset($idSection)) {
$qb->andWhere(Operator::equals(['id_section' => $idSection]));
}
$qb->execute();
}
/**
* @return Slider[]
*
* @throws DBALException|SerializerException
*/
public function getSectionSliders(int $sectionID): array
{
return $this->fetchSliders(
function (QueryBuilder $qb) use ($sectionID) {
$sectionPositions = sqlQueryBuilder()
->select('DISTINCT sis.id_slider', 'sis.position')
->from('sliders_in_sections', 'sis')
->andWhere(Operator::equals(['sis.id_section' => $sectionID]));
$qb->addSelect('sis.position AS section_position')
->joinSubQuery('sl', $sectionPositions, 'sis', 'sl.id = sis.id_slider');
},
indexBy: 'section_position',
);
}
public function getSliderPositions(?callable $spec = null): array
{
$qb = sqlQueryBuilder()
->select('sis.position AS section_position', 'sis.id_section', 'sis.id_slider', 'sl.name')
->from('sliders_in_sections', 'sis')
->leftJoin('sis', 'sliders', 'sl', 'sl.id = sis.id_slider')
->addGroupBy('sis.id_section', 'sis.position');
if ($spec !== null) {
$qb->andWhere($spec);
}
$mapped = [];
foreach ($qb->execute() as $positionInSection) {
$sectionID = $positionInSection['id_section'];
$position = $positionInSection['section_position'];
if (!isset($mapped[$sectionID])) {
$mapped[$sectionID] = [];
}
$mapped[$sectionID][$position] = $positionInSection;
}
return $mapped;
}
/**
* @return array Slider positions from config <code>($cfg['Modules']['sliders']['positions'])</code>
*/
public static function getPositions(): array
{
$positions = findModule(\Modules::SLIDERS, 'positions', default: []);
if (!array_key_exists('main', $positions)) {
$positions = array_merge(['main' => 'Hlavní'], $positions);
}
if (findModule(\Modules::SLIDERS, 'additional_section_slider')
&& !array_key_exists('additional', $positions)) {
$positions['additional'] = 'Vedlejší';
}
return $positions;
}
private static function specRandomSlider(bool $random): callable
{
return function (QueryBuilder $qb) use ($random) {
if ($random) {
$qb->orderBy('RAND()')
->setMaxResults(1);
} else {
$qb->orderBy('si.position');
}
};
}
}