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 ($cfg['Modules']['sliders']['positions']) */ 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'); } }; } }