Initial commit: is_imageslider out of the box. v2.3.2

This commit is contained in:
Isabelle Anno
2025-11-19 13:30:22 +01:00
commit 2f4716f567
100 changed files with 8635 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Cache;
use Oksydan\IsImageslider\Hook\AbstractCacheableDisplayHook;
use Oksydan\IsImageslider\Repository\HookModuleRepository;
use Oksydan\IsImageslider\Repository\ImageSliderRepository;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Core\Domain\Shop\ValueObject\ShopConstraint;
class TemplateCache
{
protected $module;
protected $context;
/**
* @var HookModuleRepository
*/
protected $hookModuleRepository;
/**
* @var Configuration
*/
protected $configuration;
/**
* @var ImageSliderRepository
*/
protected $slideRepository;
public const IS_SLIDER_DATE_CACHE_KEY = 'IS_SLIDER_DATE_CACHE_KEY';
private const DATE_TIME_FORMAT = 'Y-m-d H:i:s';
public function __construct(
\Module $module,
\Context $context,
HookModuleRepository $hookModuleRepository,
Configuration $configuration,
ImageSliderRepository $slideRepository
) {
$this->module = $module;
$this->context = $context;
$this->hookModuleRepository = $hookModuleRepository;
$this->configuration = $configuration;
$this->slideRepository = $slideRepository;
}
public function clearTemplateCache()
{
$hookedHooks = $this->hookModuleRepository->getAllHookRegisteredToModule($this->module->id);
$uniqueHooks = [];
foreach ($hookedHooks as $hook) {
if (!in_array($hook['name'], $uniqueHooks)) {
$uniqueHooks[] = $hook['name'];
}
}
foreach ($uniqueHooks as $hook) {
$this->clearCacheForHook($hook);
}
$this->setCacheValidityDateForSlider();
}
private function clearCacheForHook($hookName)
{
$displayHook = $this->getServiceFromHookName($hookName);
if ($displayHook) {
$this->module->_clearCache($displayHook->getTemplateFullPath());
}
}
private function getServiceFromHookName($hookName)
{
$serviceName = sprintf(
'oksydan.is_imageslider.hook.%s',
\Tools::toUnderscoreCase(str_replace('hook', '', $hookName))
);
$hook = $this->module->getService($serviceName);
return $hook instanceof AbstractCacheableDisplayHook ? $hook : null;
}
private function setCacheValidityDate(\DateTime $date, ShopConstraint $shopConstraint): void
{
$this->configuration->set(self::IS_SLIDER_DATE_CACHE_KEY, $date->format(self::DATE_TIME_FORMAT), $shopConstraint);
}
private function getCacheValidityDate(ShopConstraint $shopConstraint): string
{
return $this->configuration->get(self::IS_SLIDER_DATE_CACHE_KEY, '', $shopConstraint);
}
private function resetCacheValidityDate(ShopConstraint $shopConstraint): void
{
$this->configuration->set(self::IS_SLIDER_DATE_CACHE_KEY, '', $shopConstraint);
}
public function clearTemplateCacheIfNeeded(int $idShop): void
{
$now = new \DateTime();
$shopConstraint = ShopConstraint::shop($idShop);
$date = $this->getCacheValidityDate($shopConstraint);
$dateCacheKey = $date ? \DateTime::createFromFormat(self::DATE_TIME_FORMAT, $date) : null;
if ($dateCacheKey && $now > $dateCacheKey) {
$this->clearTemplateCache();
}
}
public function setCacheValidityDateForSlider(): void
{
$stores = \Shop::getShops();
foreach ($stores as $store) {
$shopConstraint = ShopConstraint::shop((int) $store['id_shop']);
$slides = $this->slideRepository->getSimpleActiveSliderByStoreId(
$shopConstraint->getShopId()->getValue()
);
$this->setCacheValidityDateFromSliders($slides, $shopConstraint);
}
}
private function setCacheValidityDateFromSliders(array $slides, ShopConstraint $shopConstraint): void
{
$closestDate = null;
$now = new \DateTime();
foreach ($slides as $slide) {
$dateFrom = $slide['display_from'] ? \DateTime::createFromFormat(self::DATE_TIME_FORMAT, $slide['display_from']) : null;
$dateTo = $slide['display_to'] ? \DateTime::createFromFormat(self::DATE_TIME_FORMAT, $slide['display_to']) : null;
if ($dateFrom > $now && (($dateFrom && $closestDate && $closestDate > $dateFrom) || !$closestDate)) {
$closestDate = $dateFrom;
}
if ($dateTo > $now && (($dateTo && $closestDate && $closestDate > $dateTo) || !$closestDate)) {
$closestDate = $dateTo;
}
}
if ($closestDate) {
$this->setCacheValidityDate($closestDate, $shopConstraint);
} else {
$this->resetCacheValidityDate($shopConstraint);
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Configuration;
class SliderConfiguration
{
public const HOMESLIDER_SPEED = 'HOMESLIDER_SPEED';
public const HOMESLIDER_PAUSE_ON_HOVER = 'HOMESLIDER_PAUSE_ON_HOVER';
public const HOMESLIDER_WRAP = 'HOMESLIDER_WRAP';
public function getSliderSpeed()
{
return \Configuration::get(SliderConfiguration::HOMESLIDER_SPEED);
}
public function getSliderPauseOnHover()
{
return \Configuration::get(SliderConfiguration::HOMESLIDER_PAUSE_ON_HOVER);
}
public function getSliderWrap()
{
return \Configuration::get(SliderConfiguration::HOMESLIDER_WRAP);
}
}

View File

@@ -0,0 +1,317 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Controller;
use Oksydan\IsImageslider\Cache\TemplateCache;
use Oksydan\IsImageslider\Entity\ImageSlider;
use Oksydan\IsImageslider\Exceptions\DateRangeNotValidException;
use Oksydan\IsImageslider\Filter\ImageSliderFileters;
use Oksydan\IsImageslider\Handler\FileEraser;
use Oksydan\IsImageslider\Translations\TranslationDomains;
use PrestaShop\PrestaShop\Core\Grid\Position\Exception\PositionDataException;
use PrestaShop\PrestaShop\Core\Grid\Position\Exception\PositionUpdateException;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Entity\Shop;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class IsImagesliderController extends FrameworkBundleAdminController
{
/**
* @var FileEraser
*/
private $fileEraser;
/**
* @var array
*/
private $languages;
/**
* @var TemplateCache
*/
private $templateCache;
public function __construct(FileEraser $fileEraser, $languages, TemplateCache $templateCache)
{
$this->fileEraser = $fileEraser;
$this->languages = $languages;
$this->templateCache = $templateCache;
}
public function index(ImageSliderFileters $filters): Response
{
$imageSliderGridFactory = $this->get('oksydan.is_imageslider.grid.image_slider_grid_factory');
$imageSliderGrid = $imageSliderGridFactory->getGrid($filters);
$configurationForm = $this->get('oksydan.is_imageslider.image_slider_configuration.form_handler')->getForm();
return $this->render('@Modules/is_imageslider/views/templates/admin/index.html.twig', [
'translationDomain' => TranslationDomains::TRANSLATION_DOMAIN_ADMIN,
'imageSliderkGrid' => $this->presentGrid($imageSliderGrid),
'configurationForm' => $configurationForm->createView(),
'help_link' => false,
]);
}
public function create(Request $request): Response
{
$formDataHandler = $this->get('oksydan.is_imageslider.form.identifiable_object.builder.image_slider_form_builder');
$form = $formDataHandler->getForm();
$form->handleRequest($request);
$formHandler = $this->get('oksydan.is_imageslider.form.identifiable_object.handler.image_slider_form_handler');
try {
$result = $formHandler->handle($form);
if (null !== $result->getIdentifiableObjectId()) {
$this->addFlash(
'success',
$this->trans('Successful creation.', 'Admin.Notifications.Success')
);
$this->clearTemplateCache();
return $this->redirectToRoute('is_imageslider_controller');
}
} catch (\Exception $e) {
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
}
return $this->render('@Modules/is_imageslider/views/templates/admin/form.html.twig', [
'imageSliderForm' => $form->createView(),
'title' => $this->trans('Image slider', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'help_link' => false,
]);
}
public function edit(Request $request, int $slideId): Response
{
$formBuilder = $this->get('oksydan.is_imageslider.form.identifiable_object.builder.image_slider_form_builder');
$form = $formBuilder->getFormFor((int) $slideId);
$form->handleRequest($request);
$formHandler = $this->get('oksydan.is_imageslider.form.identifiable_object.handler.image_slider_form_handler');
try {
$result = $formHandler->handleFor($slideId, $form);
if (null !== $result->getIdentifiableObjectId()) {
$this->addFlash(
'success',
$this->trans('Successful edition.', 'Admin.Notifications.Success')
);
$this->clearTemplateCache();
return $this->redirectToRoute('is_imageslider_controller');
}
} catch (\Exception $e) {
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
}
return $this->render('@Modules/is_imageslider/views/templates/admin/form.html.twig', [
'imageSliderForm' => $form->createView(),
'title' => $this->trans('Image slider edition', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'help_link' => false,
]);
}
public function delete(Request $request, int $slideId): Response
{
$imageSlide = $this->getDoctrine()
->getRepository(ImageSlider::class)
->find($slideId);
if (!empty($imageSlide)) {
$multistoreContext = $this->get('prestashop.adapter.shop.context');
$entityManager = $this->get('doctrine.orm.entity_manager');
if ($multistoreContext->isAllShopContext()) {
$imageSlide->clearShops();
foreach ($this->languages as $language) {
$langId = (int) $language['id_lang'];
$imageSliderLang = $imageSlide->getImageSliderLangByLangId($langId);
if ($imageSliderLang->getImage()) {
$this->eraseFile($imageSliderLang->getImage());
}
if ($imageSliderLang->getImageMobile()) {
$this->eraseFile($imageSliderLang->getImageMobile());
}
}
$entityManager->remove($imageSlide);
} else {
$shopList = $this->getDoctrine()
->getRepository(Shop::class)
->findBy(['id' => $multistoreContext->getContextListShopID()]);
foreach ($shopList as $shop) {
$imageSlide->removeShop($shop);
$entityManager->flush();
}
if (count($imageSlide->getShops()) === 0) {
$entityManager->remove($imageSlide);
}
}
$this->clearTemplateCache();
$entityManager->flush();
$this->addFlash(
'success',
$this->trans('Successful deletion.', 'Admin.Notifications.Success')
);
return $this->redirectToRoute('is_imageslider_controller');
}
$this->addFlash(
'error',
$this->trans('Cannot find slider %d', TranslationDomains::TRANSLATION_DOMAIN_ADMIN, ['%d' => $slideId])
);
return $this->redirectToRoute('is_imageslider_controller');
}
/**
* @param Request $request
*
* @return Response
*/
public function saveConfiguration(Request $request): Response
{
$redirectResponse = $this->redirectToRoute('is_imageslider_controller');
$form = $this->get('oksydan.is_imageslider.image_slider_configuration.form_handler')->getForm();
$form->handleRequest($request);
if (!$form->isSubmitted()) {
return $redirectResponse;
}
if ($form->isValid()) {
$data = $form->getData();
$saveErrors = $this->get('oksydan.is_imageslider.image_slider_configuration.form_handler')->save($data);
if (0 === count($saveErrors)) {
$this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success'));
$this->clearTemplateCache();
return $redirectResponse;
}
}
$formErrors = [];
foreach ($form->getErrors(true) as $error) {
$formErrors[] = $error->getMessage();
}
$this->flashErrors($formErrors);
return $redirectResponse;
}
/**
* @param Request $request
* @param int $slideId
*
* @return Response
*/
public function toggleStatus(Request $request, int $slideId): Response
{
$entityManager = $this->get('doctrine.orm.entity_manager');
$imageSlide = $entityManager
->getRepository(ImageSlider::class)
->findOneBy(['id' => $slideId]);
if (empty($imageSlide)) {
return $this->json([
'status' => false,
'message' => sprintf('Image slide %d doesn\'t exist', $slideId),
]);
}
try {
$imageSlide->setActive(!$imageSlide->getActive());
$entityManager->flush();
$this->clearTemplateCache();
$response = [
'status' => true,
'message' => $this->trans('The status has been successfully updated.', 'Admin.Notifications.Success'),
];
} catch (\Exception $e) {
$response = [
'status' => false,
'message' => sprintf(
'There was an error while updating the status of slide %d: %s',
$slideId,
$e->getMessage()
),
];
}
return $this->json($response);
}
public function updatePositionAction(Request $request): Response
{
try {
$positionsData = [
'positions' => $request->request->get('positions'),
];
$positionDefinition = $this->get('oksydan.is_imageslider.grid.position_definition');
$positionUpdateFactory = $this->get('prestashop.core.grid.position.position_update_factory');
$positionUpdate = $positionUpdateFactory->buildPositionUpdate($positionsData, $positionDefinition);
$updater = $this->get('prestashop.core.grid.position.doctrine_grid_position_updater');
$updater->update($positionUpdate);
$this->clearTemplateCache();
$this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success'));
} catch (PositionDataException|PositionUpdateException $e) {
$errors = [$e->toArray()];
$this->flashErrors($errors);
}
return $this->redirectToRoute('is_imageslider_controller');
}
private function eraseFile(string $fileName): bool
{
return $this->fileEraser->remove($fileName);
}
private function clearTemplateCache()
{
$this->templateCache->clearTemplateCache();
}
/**
* Provides translated error messages for exceptions
*
* @return array
*/
private function getErrorMessages(): array
{
return [
DateRangeNotValidException::class => [
$this->trans(
'The selected date range is not valid. Date to must be greater than date from.',
TranslationDomains::TRANSLATION_DOMAIN_EXCEPTION
),
],
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,245 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use PrestaShopBundle\Entity\Shop;
/**
* @ORM\Entity(repositoryClass="Oksydan\IsImageslider\Repository\ImageSliderRepository")
*
* @ORM\Table()
*/
class ImageSlider
{
/**
* @var int
*
* @ORM\Id
*
* @ORM\Column(name="id_slide", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var bool
*
* @ORM\Column(name="active", type="boolean")
*/
private $active;
/**
* @var int
*
* @ORM\Column(name="position", type="integer")
*/
private $position;
/**
* @var \DateTime
*
* @ORM\Column(name="display_from", type="datetime", nullable=true)
*/
private $display_from;
/**
* @var \DateTime
*
* @ORM\Column(name="display_to", type="datetime", nullable=true)
*/
private $display_to;
/**
* @ORM\OneToMany(targetEntity="Oksydan\IsImageslider\Entity\ImageSliderLang", cascade={"persist", "remove"}, mappedBy="imageSlide")
*/
private $sliderLangs;
/**
* @ORM\ManyToMany(targetEntity="PrestaShopBundle\Entity\Shop", cascade={"persist"})
*
* @ORM\JoinTable(
* joinColumns={@ORM\JoinColumn(name="id_slide", referencedColumnName="id_slide")},
* inverseJoinColumns={@ORM\JoinColumn(name="id_shop", referencedColumnName="id_shop", onDelete="CASCADE")}
* )
*/
private $shops;
public function __construct()
{
$this->shops = new ArrayCollection();
$this->sliderLangs = new ArrayCollection();
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return bool
*/
public function getActive(): bool
{
return $this->active;
}
/**
* @param bool $active
*
* @return ImageSlider $this
*/
public function setActive(bool $active): ImageSlider
{
$this->active = $active;
return $this;
}
/**
* @return int
*/
public function getPosition(): int
{
return $this->position;
}
/**
* @param int $position
*
* @return ImageSlider $this
*/
public function setPosition(int $position): ImageSlider
{
$this->position = $position;
return $this;
}
/**
* @return \DateTime
*/
public function getDisplayFrom(): \DateTime
{
return $this->display_from;
}
/**
* @param \DateTime $display_from
*
* @return ImageSlider $this
*/
public function setDisplayFrom(\DateTime $display_from): ImageSlider
{
$this->display_from = $display_from;
return $this;
}
/**
* @return \DateTime
*/
public function getDisplayTo(): \DateTime
{
return $this->display_to;
}
/**
* @param \DateTime $display_to
*
* @return ImageSlider $this
*/
public function setDisplayTo(\DateTime $display_to): ImageSlider
{
$this->display_to = $display_to;
return $this;
}
/**
* @param Shop $shop
*
* @return ImageSlider $this
*/
public function addShop(Shop $shop): ImageSlider
{
$this->shops[] = $shop;
return $this;
}
/**
* @param Shop $shop
*
* @return ImageSlider $this
*/
public function removeShop(Shop $shop): ImageSlider
{
$this->shops->removeElement($shop);
return $this;
}
/**
* @return Collection
*/
public function getShops(): Collection
{
return $this->shops;
}
/**
* @return ImageSlider $this
*/
public function clearShops(): ImageSlider
{
$this->shops->clear();
return $this;
}
/**
* @return ArrayCollection
*/
public function getSliderLangs()
{
return $this->sliderLangs;
}
/**
* @param int $langId
*
* @return ImageSliderLang|null
*/
public function getImageSliderLangByLangId(int $langId)
{
foreach ($this->sliderLangs as $sliderLang) {
if ($langId === $sliderLang->getLang()->getId()) {
return $sliderLang;
}
}
return null;
}
/**
* @param ImageSliderLang $sliderLang
*
* @return ImageSlider $this
*/
public function addImageSliderLang(ImageSliderLang $sliderLang): ImageSlider
{
$sliderLang->setImageSlider($this);
$this->sliderLangs->add($sliderLang);
return $this;
}
}

View File

@@ -0,0 +1,240 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Entity;
use Doctrine\ORM\Mapping as ORM;
use PrestaShopBundle\Entity\Lang;
/**
* @ORM\Table()
*
* @ORM\Entity
*/
class ImageSliderLang
{
/**
* @var ImageSlider
*
* @ORM\Id
*
* @ORM\ManyToOne(targetEntity="Oksydan\IsImageslider\Entity\ImageSlider", inversedBy="imageSlideLang")
*
* @ORM\JoinColumn(name="id_slide", referencedColumnName="id_slide", nullable=false)
*/
private $imageSlide;
/**
* @var Lang
*
* @ORM\Id
*
* @ORM\ManyToOne(targetEntity="PrestaShopBundle\Entity\Lang")
*
* @ORM\JoinColumn(name="id_lang", referencedColumnName="id_lang", nullable=false, onDelete="CASCADE")
*/
private $lang;
/**
* @var string
*
* @ORM\Column(name="title", type="text")
*/
private $title;
/**
* @var string
*
* @ORM\Column(name="legend", type="text")
*/
private $legend;
/**
* @var string
*
* @ORM\Column(name="url", type="text")
*/
private $url;
/**
* @var string
*
* @ORM\Column(name="description", type="text")
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="image", type="text")
*/
private $image;
/**
* @var string
*
* @ORM\Column(name="image_mobile", type="text")
*/
private $imageMobile;
/**
* @return ImageSlider
*/
public function getImageSlider(): ImageSlider
{
return $this->imageSlide;
}
/**
* @param ImageSlider $imageSlide
*
* @return ImageSliderLang $this
*/
public function setImageSlider(ImageSlider $imageSlide): ImageSliderLang
{
$this->imageSlide = $imageSlide;
return $this;
}
/**
* @return string
*/
public function getTitle(): string
{
return $this->title;
}
/**
* @param string $title
*
* @return ImageSliderLang $this
*/
public function setTitle(string $title): ImageSliderLang
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getLegend(): string
{
return $this->legend;
}
/**
* @param string $legend
*
* @return ImageSliderLang $this
*/
public function setLegend(string $legend): ImageSliderLang
{
$this->legend = $legend;
return $this;
}
/**
* @return string
*/
public function getUrl(): string
{
return $this->url;
}
/**
* @param string $url
*
* @return ImageSliderLang $this
*/
public function setUrl(string $url): ImageSliderLang
{
$this->url = $url;
return $this;
}
/**
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
/**
* @param string $description
*
* @return ImageSliderLang $this
*/
public function setDescription(string $description): ImageSliderLang
{
$this->description = $description;
return $this;
}
/**
* @return string|null
*/
public function getImage(): ?string
{
return $this->image;
}
/**
* @param string $image
*
* @return ImageSliderLang $this
*/
public function setImage(string $image): ImageSliderLang
{
$this->image = $image;
return $this;
}
/**
* @return string|null
*/
public function getImageMobile(): ?string
{
return $this->imageMobile;
}
/**
* @param string $imageMobile
*
* @return ImageSliderLang $this
*/
public function setImageMobile(string $imageMobile): ImageSliderLang
{
$this->imageMobile = $imageMobile;
return $this;
}
/**
* @return Lang
*/
public function getLang(): Lang
{
return $this->lang;
}
/**
* @param Lang $lang
*
* @return ImageSliderLang $this
*/
public function setLang(Lang $lang): ImageSliderLang
{
$this->lang = $lang;
return $this;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Exceptions;
class DatabaseYamlFileNotExistsException extends \ErrorException
{
}

View File

@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Exceptions;
class DateRangeNotValidException extends \ErrorException
{
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Filter;
use PrestaShop\PrestaShop\Core\Search\Filters;
/**
* Class ProductFilter proves default filters for our products grid
*/
final class ImageSliderFileters extends Filters
{
/**
* {@inheritdoc}
*/
public static function getDefaults(): array
{
return [
'limit' => 10,
'offset' => 0,
'orderBy' => 'position',
'sortOrder' => 'ASC',
'filters' => [],
];
}
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form\DataConfiguration;
use Oksydan\IsImageslider\Configuration\SliderConfiguration;
use PrestaShop\PrestaShop\Core\Configuration\AbstractMultistoreConfiguration;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Handles configuration data for demo multistore configuration options.
*/
final class ImageSliderDataConfiguration extends AbstractMultistoreConfiguration
{
private const CONFIGURATION_FIELDS = [
'speed',
'pause',
'wrap',
];
/**
* @return OptionsResolver
*/
protected function buildResolver(): OptionsResolver
{
return (new OptionsResolver())
->setDefined(self::CONFIGURATION_FIELDS)
->setAllowedTypes('speed', 'string')
->setAllowedTypes('pause', 'bool')
->setAllowedTypes('wrap', 'bool');
}
/**
* {@inheritdoc}
*/
public function getConfiguration(): array
{
$return = [];
$shopConstraint = $this->getShopConstraint();
$return['speed'] = $this->configuration->get(SliderConfiguration::HOMESLIDER_SPEED, null, $shopConstraint);
$return['pause'] = $this->configuration->get(SliderConfiguration::HOMESLIDER_PAUSE_ON_HOVER, null, $shopConstraint);
$return['wrap'] = $this->configuration->get(SliderConfiguration::HOMESLIDER_WRAP, null, $shopConstraint);
return $return;
}
/**
* {@inheritdoc}
*/
public function updateConfiguration(array $configuration): array
{
$shopConstraint = $this->getShopConstraint();
$this->updateConfigurationValue(SliderConfiguration::HOMESLIDER_SPEED, 'speed', $configuration, $shopConstraint);
$this->updateConfigurationValue(SliderConfiguration::HOMESLIDER_PAUSE_ON_HOVER, 'pause', $configuration, $shopConstraint);
$this->updateConfigurationValue(SliderConfiguration::HOMESLIDER_WRAP, 'wrap', $configuration, $shopConstraint);
return [];
}
}

View File

@@ -0,0 +1,210 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form\DataHandler;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Oksydan\IsImageslider\Entity\ImageSlider;
use Oksydan\IsImageslider\Entity\ImageSliderLang;
use Oksydan\IsImageslider\Exceptions\DateRangeNotValidException;
use Oksydan\IsImageslider\Handler\FileEraser;
use Oksydan\IsImageslider\Handler\FileUploader;
use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataHandler\FormDataHandlerInterface;
use PrestaShopBundle\Entity\Repository\LangRepository;
use PrestaShopBundle\Entity\Shop;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class ImageSliderFormDataHandler implements FormDataHandlerInterface
{
/**
* @var EntityRepository
*/
private $imageSliderRepository;
/**
* @var LangRepository
*/
private $langRepository;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var FileUploader
*/
private $fileUploader;
/**
* @var FileEraser
*/
private $fileEraser;
/**
* @var array
*/
private $languages;
public function __construct(
EntityRepository $imageSliderRepository,
LangRepository $langRepository,
EntityManagerInterface $entityManager,
FileUploader $fileUploader,
FileEraser $fileEraser,
array $languages
) {
$this->imageSliderRepository = $imageSliderRepository;
$this->langRepository = $langRepository;
$this->entityManager = $entityManager;
$this->fileUploader = $fileUploader;
$this->fileEraser = $fileEraser;
$this->languages = $languages;
}
/**
* {@inheritdoc}
*/
public function create(array $data): int
{
$this->assertSliderDataRangeActivity($data);
$imageSlide = new ImageSlider();
$imageSlide->setActive($data['active']);
$imageSlide->setDisplayFrom($data['display_from'] ?? new \DateTime());
$imageSlide->setDisplayTo($data['display_to'] ?? new \DateTime());
$imageSlide->setPosition($this->imageSliderRepository->getHighestPosition() + 1);
$this->addAssociatedShops($imageSlide, $data['shop_association'] ?? null);
foreach ($this->languages as $language) {
$langId = (int) $language['id_lang'];
$lang = $this->langRepository->findOneById($langId);
$imageSliderLang = new ImageSliderLang();
$imageSliderLang
->setLang($lang)
->setTitle($data['title'][$langId] ?? '')
->setUrl($data['url'][$langId] ?? '')
->setLegend($data['legend'][$langId] ?? '')
->setDescription($data['description'][$langId] ?? '');
if (!empty($data['image'][$langId])) {
$imageSliderLang->setImage($this->uploadFile($data['image'][$langId]));
}
if (!empty($data['image_mobile'][$langId])) {
$imageSliderLang->setImageMobile($this->uploadFile($data['image_mobile'][$langId]));
}
$imageSlide->addImageSliderLang($imageSliderLang);
}
$this->entityManager->persist($imageSlide);
$this->entityManager->flush();
return $imageSlide->getId();
}
/**
* {@inheritdoc}
*/
public function update($id, array $data): int
{
$this->assertSliderDataRangeActivity($data);
$imageSlide = $this->entityManager->getRepository(ImageSlider::class)->find($id);
$imageSlide->setActive($data['active']);
$imageSlide->setDisplayFrom($data['display_from'] ?? new \DateTime());
$imageSlide->setDisplayTo($data['display_to'] ?? new \DateTime());
$this->addAssociatedShops($imageSlide, $data['shop_association'] ?? null);
foreach ($this->languages as $language) {
$langId = (int) $language['id_lang'];
$imageSliderLang = $imageSlide->getImageSliderLangByLangId($langId);
$newImageSliderLang = false;
if (null === $imageSliderLang) {
$imageSliderLang = new ImageSliderLang();
$lang = $this->langRepository->findOneById($langId);
$imageSliderLang->setLang($lang);
$newImageSliderLang = true;
}
$imageSliderLang
->setTitle($data['title'][$langId] ?? '')
->setUrl($data['url'][$langId] ?? '')
->setLegend($data['legend'][$langId] ?? '')
->setDescription($data['description'][$langId] ?? '');
if (!empty($data['image'][$langId])) {
if ($imageSliderLang->getImage() !== null) {
$this->eraseFile($imageSliderLang->getImage());
}
$imageSliderLang->setImage($this->uploadFile($data['image'][$langId]));
}
if (!empty($data['image_mobile'][$langId])) {
if ($imageSliderLang->getImage() !== null) {
$this->eraseFile($imageSliderLang->getImageMobile());
}
$imageSliderLang->setImageMobile($this->uploadFile($data['image_mobile'][$langId]));
}
if ($newImageSliderLang) {
$imageSlide->addImageSliderLang($imageSliderLang);
}
}
$this->entityManager->flush();
return $imageSlide->getId();
}
/**
* @params array $data
*
* @return void
*
* @throws DateRangeNotValidException
*/
private function assertSliderDataRangeActivity($data): void
{
if (!empty($data['display_from']) && !empty($data['display_to'])) {
if ($data['display_from'] > $data['display_to']) {
throw new DateRangeNotValidException();
}
}
}
/**
* @param ImageSlider $imageSlide
* @param array|null $shopIdList
*/
private function addAssociatedShops(ImageSlider &$imageSlide, array $shopIdList = null): void
{
$imageSlide->clearShops();
if (empty($shopIdList)) {
return;
}
foreach ($shopIdList as $shopId) {
$shop = $this->entityManager->getRepository(Shop::class)->find($shopId);
$imageSlide->addShop($shop);
}
}
private function uploadFile(UploadedFile $file): string
{
return $this->fileUploader->upload($file);
}
private function eraseFile(string $fileName): bool
{
return $this->fileEraser->remove($fileName);
}
}

View File

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form;
use Oksydan\IsImageslider\Configuration\SliderConfiguration;
use Oksydan\IsImageslider\Translations\TranslationDomains;
use PrestaShopBundle\Form\Admin\Type\MultistoreConfigurationType;
use PrestaShopBundle\Form\Admin\Type\SwitchType;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Range;
class ImageSliderConfigurationType extends TranslatorAwareType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$minTime = 1000;
$maxTime = 60000;
$rangeInvalidMessage = $this->trans(
'This field value have to be between %min%ms and %max%ms.',
TranslationDomains::TRANSLATION_DOMAIN_ADMIN,
[
'%min%' => $minTime,
'%max%' => $maxTime,
]
);
$builder
->add('speed', TextType::class, [
'attr' => ['class' => 'col-md-4 col-lg-2'],
'required' => true,
'label' => $this->trans('Speed', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'help' => $this->trans('The duration of the transition between two slides.', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'multistore_configuration_key' => SliderConfiguration::HOMESLIDER_SPEED,
'constraints' => [
new Range([
'min' => $minTime,
'max' => $maxTime,
'invalidMessage' => $rangeInvalidMessage,
'maxMessage' => $rangeInvalidMessage,
'minMessage' => $rangeInvalidMessage,
]),
],
])
->add('pause', SwitchType::class, [
'label' => $this->trans('Pause on hover', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'help' => $this->trans('Stop sliding when the mouse cursor is over the slideshow.', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'multistore_configuration_key' => SliderConfiguration::HOMESLIDER_PAUSE_ON_HOVER,
])
->add('wrap', SwitchType::class, [
'label' => $this->trans('Wrap', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'help' => $this->trans('Loop or stop after the last slide.', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'multistore_configuration_key' => SliderConfiguration::HOMESLIDER_WRAP,
]);
}
/**
* {@inheritdoc}
*
* @see MultistoreConfigurationTypeExtension
*/
public function getParent(): string
{
return MultistoreConfigurationType::class;
}
}

View File

@@ -0,0 +1,166 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form;
use Oksydan\IsImageslider\Translations\TranslationDomains;
use Oksydan\IsImageslider\Type\TranslatableFile;
use PrestaShopBundle\Form\Admin\Type\FormattedTextareaType;
use PrestaShopBundle\Form\Admin\Type\ImagePreviewType;
use PrestaShopBundle\Form\Admin\Type\ShopChoiceTreeType;
use PrestaShopBundle\Form\Admin\Type\SwitchType;
use PrestaShopBundle\Form\Admin\Type\TranslatableType;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\Validator\Constraints\NotBlank;
class ImageSliderType extends TranslatorAwareType
{
/**
* @var bool
*/
private $isMultistoreUsed;
/**
* @param TranslatorInterface $translator
* @param array $locales
* @param bool $isMultistoreUsed
*/
public function __construct(
TranslatorInterface $translator,
array $locales,
bool $isMultistoreUsed
) {
parent::__construct($translator, $locales);
$this->isMultistoreUsed = $isMultistoreUsed;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$isEdit = !empty($options['data']['image']);
$imageConstrains = [
new File([
'mimeTypes' => [
'image/jpeg',
'image/png',
],
]),
];
if (!$isEdit) {
$imageConstrains[] = new NotBlank();
}
$builder
->add('image_preview', TranslatableType::class, [
'type' => ImagePreviewType::class,
'label' => $this->trans('Image preview', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'required' => false,
])
->add('image', TranslatableFile::class, [
'type' => FileType::class,
'label' => $this->trans('Image', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'options' => [
'data_class' => null,
'constraints' => $imageConstrains,
],
'required' => true,
])
->add('image_mobile_preview', TranslatableType::class, [
'type' => ImagePreviewType::class,
'label' => $this->trans('Image mobile preview', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'required' => false,
])
->add('image_mobile', TranslatableFile::class, [
'type' => FileType::class,
'label' => $this->trans('Image mobile', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'options' => [
'data_class' => null,
'constraints' => $imageConstrains,
],
'required' => true,
])
->add('title', TranslatableType::class, [
'type' => TextType::class,
'label' => $this->trans('Title', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'required' => false,
])
->add('legend', TranslatableType::class, [
'type' => TextType::class,
'label' => $this->trans('Legend', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'required' => false,
])
->add('url', TranslatableType::class, [
'type' => TextType::class,
'label' => $this->trans('Link', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'locales' => $this->locales,
'required' => true,
'options' => [
'constraints' => [
new NotBlank(),
],
],
])
->add('description', TranslatableType::class, [
'type' => FormattedTextareaType::class,
'locales' => $this->locales,
'label' => $this->trans('Description', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'required' => false,
])
->add('active', SwitchType::class, [
'label' => $this->trans('Active', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'required' => true,
])
->add('display_from', DateTimeType::class, [
'label' => $this->trans('Display from', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'required' => true,
'widget' => 'single_text',
'html5' => true,
'input' => 'datetime',
'with_seconds' => true,
])
->add('display_to', DateTimeType::class, [
'label' => $this->trans('Display to', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'required' => true,
'widget' => 'single_text',
'html5' => true,
'input' => 'datetime',
'with_seconds' => true,
]);
if ($this->isMultistoreUsed) {
$builder->add(
'shop_association',
ShopChoiceTreeType::class,
[
'label' => $this->trans('Shop associations', TranslationDomains::TRANSLATION_DOMAIN_ADMIN),
'constraints' => [
new NotBlank([
'message' => $this->trans(
'You have to select at least one shop to associate this item with',
'Admin.Notifications.Error'
),
]),
],
]
);
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form\Provider;
use PrestaShop\PrestaShop\Core\Configuration\DataConfigurationInterface;
use PrestaShop\PrestaShop\Core\Form\FormDataProviderInterface;
class ImageSliderConfigurationFormDataProvider implements FormDataProviderInterface
{
/**
* @var DataConfigurationInterface
*/
private $imageSlideConfigurationDataConfiguration;
/**
* @param DataConfigurationInterface $imageSlideConfigurationDataConfiguration
*/
public function __construct(DataConfigurationInterface $imageSlideConfigurationDataConfiguration)
{
$this->imageSlideConfigurationDataConfiguration = $imageSlideConfigurationDataConfiguration;
}
/**
* {@inheritdoc}
*/
public function getData(): array
{
return $this->imageSlideConfigurationDataConfiguration->getConfiguration();
}
/**
* {@inheritdoc}
*/
public function setData(array $data): array
{
return $this->imageSlideConfigurationDataConfiguration->updateConfiguration($data);
}
}

View File

@@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Form\Provider;
use Doctrine\ORM\EntityRepository;
use Oksydan\IsImageslider\Provider\ImageProviderInterface;
use PrestaShop\PrestaShop\Adapter\Shop\Context;
use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataProvider\FormDataProviderInterface;
use PrestaShopBundle\Entity\Repository\LangRepository;
class ImageSliderFormDataProvider implements FormDataProviderInterface
{
/**
* @var EntityRepository
*/
private $repository;
/**
* @var ImageProviderInterface
*/
private $imagesliderImageThumbProvider;
/**
* @var LangRepository
*/
private $langRepository;
/**
* @var string
*/
private $placeholderImage;
/**
* @var Context
*/
private $shopContext;
/**
* ImageSliderFormDataProvider constructor.
*
* @param EntityRepository $repository
*/
public function __construct(
EntityRepository $repository,
ImageProviderInterface $imagesliderImageThumbProvider,
LangRepository $langRepository,
string $placeholderImage,
Context $shopContext
) {
$this->repository = $repository;
$this->shopContext = $shopContext;
$this->imagesliderImageThumbProvider = $imagesliderImageThumbProvider;
$this->placeholderImage = $placeholderImage;
$this->langRepository = $langRepository;
}
/**
* @param mixed $id
*
* @return array
*/
public function getData($id): array
{
$imageSlide = $this->repository->findOneById((int) $id);
$shopIds = [];
$slideData = [];
foreach ($imageSlide->getShops() as $shop) {
$shopIds[] = $shop->getId();
}
$slideData['shop_association'] = $shopIds;
$slideData['active'] = $imageSlide->getActive();
$slideData['display_from'] = $imageSlide->getDisplayFrom();
$slideData['display_to'] = $imageSlide->getDisplayTo();
foreach ($imageSlide->getSliderLangs() as $imageSlideLang) {
$slideData['title'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getTitle();
$slideData['legend'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getLegend();
$slideData['url'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getUrl();
$slideData['description'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getDescription();
$slideData['image'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getImage();
$slideData['image_mobile'][$imageSlideLang->getLang()->getId()] = $imageSlideLang->getImageMobile();
$slideData['image_preview'][$imageSlideLang->getLang()->getId()] = $this->imagesliderImageThumbProvider->getPath($imageSlideLang->getImage()) ?? $this->placeholderImage;
$slideData['image_mobile_preview'][$imageSlideLang->getLang()->getId()] = $this->imagesliderImageThumbProvider->getPath($imageSlideLang->getImageMobile()) ?? $this->placeholderImage;
}
return $slideData;
}
/**
* @return array
*/
private function getImagePreviewPlaceholder(): array
{
$imagePreview = [];
$languages = $this->langRepository->findBy(['active' => true]);
foreach ($languages as $lang) {
$imagePreview[$lang->getId()] = $this->placeholderImage;
}
return $imagePreview;
}
/**
* @return array
*/
public function getDefaultData(): array
{
return [
'image_preview' => $this->getImagePreviewPlaceholder(),
'image_mobile_preview' => $this->getImagePreviewPlaceholder(),
'title' => [],
'legend' => [],
'url' => [],
'description' => [],
'active' => false,
'display_from' => new \DateTime(),
'display_to' => new \DateTime(),
'shop_association' => $this->shopContext->getContextListShopID(),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Grid\Data\Factory;
use Oksydan\IsImageslider\Provider\ImageProviderInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\Factory\GridDataFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\GridData;
use PrestaShop\PrestaShop\Core\Grid\Record\RecordCollection;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
final class ImageSliderGridDataFactory implements GridDataFactoryInterface
{
/**
* @var GridDataFactoryInterface
*/
private $doctrineImageSliderDataFactory;
/**
* @var ImageProviderInterface
*/
private $imagesliderImageThumbProvider;
/**
* @param GridDataFactoryInterface $doctrineImageSliderDataFactory
* @param ImageProviderInterface $imagesliderImageThumbProvider
*/
public function __construct(
GridDataFactoryInterface $doctrineImageSliderDataFactory,
ImageProviderInterface $imagesliderImageThumbProvider
) {
$this->doctrineImageSliderDataFactory = $doctrineImageSliderDataFactory;
$this->imagesliderImageThumbProvider = $imagesliderImageThumbProvider;
}
/**
* {@inheritdoc}
*/
public function getData(SearchCriteriaInterface $searchCriteria)
{
$languageData = $this->doctrineImageSliderDataFactory->getData($searchCriteria);
$modifiedRecords = $this->applyModification(
$languageData->getRecords()->all()
);
return new GridData(
new RecordCollection($modifiedRecords),
$languageData->getRecordsTotal(),
$languageData->getQuery()
);
}
/**
* @param array $sliders
*
* @return array
*/
private function applyModification(array $sliders)
{
foreach ($sliders as $i => $slider) {
$sliders[$i]['image'] = $this->imagesliderImageThumbProvider->getPath($slider['image']);
}
return $sliders;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,150 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Grid\Definition\Factory;
use Oksydan\IsImageslider\Translations\TranslationDomains;
use PrestaShop\PrestaShop\Core\Grid\Action\Bulk\BulkActionCollection;
use PrestaShop\PrestaShop\Core\Grid\Action\GridActionCollection;
use PrestaShop\PrestaShop\Core\Grid\Action\Row\RowActionCollection;
use PrestaShop\PrestaShop\Core\Grid\Action\Row\Type\LinkRowAction;
use PrestaShop\PrestaShop\Core\Grid\Column\ColumnCollection;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ActionColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ImageColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\PositionColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\AbstractGridDefinitionFactory;
use PrestaShop\PrestaShop\Core\Grid\Filter\FilterCollection;
class ImageSliderGridDefinitionFactory extends AbstractGridDefinitionFactory
{
public const GRID_ID = 'is_imageslider';
/**
* {@inheritdoc}
*/
protected function getId()
{
return self::GRID_ID;
}
/**
* {@inheritdoc}
*/
protected function getName()
{
return $this->trans('Image slider', [], TranslationDomains::TRANSLATION_DOMAIN_ADMIN);
}
/**
* {@inheritdoc}
*/
protected function getColumns()
{
return (new ColumnCollection())
->add(
(new PositionColumn('position'))
->setName($this->trans('Position', [], 'Admin.Global'))
->setOptions([
'id_field' => 'id_slide',
'position_field' => 'position',
'update_route' => 'is_imageslider_controller_update_positions',
'update_method' => 'POST',
])
)
->add(
(new ImageColumn('image'))
->setName($this->trans('Image', [], 'Admin.Global'))
->setOptions([
'src_field' => 'image',
])
)
->add(
(new DataColumn('title'))
->setName($this->trans('Title', [], 'Admin.Global'))
->setOptions([
'field' => 'title',
])
)
->add(
(new DataColumn('id_slide'))
->setName($this->trans('ID', [], 'Admin.Global'))
->setOptions([
'field' => 'id_slide',
])
)
->add(
(new DataColumn('title'))
->setName($this->trans('Title', [], 'Admin.Global'))
->setOptions([
'field' => 'title',
])
)
->add(
(new ToggleColumn('active'))
->setName($this->trans('Displayed', [], 'Admin.Global'))
->setOptions([
'field' => 'active',
'primary_field' => 'id_slide',
'route' => 'is_imageslider_controller_toggle_status',
'route_param_name' => 'slideId',
])
)
->add(
(new ActionColumn('actions'))
->setOptions([
'actions' => (new RowActionCollection())
->add(
(new LinkRowAction('edit'))
->setIcon('edit')
->setOptions([
'route' => 'is_imageslider_controller_edit',
'route_param_name' => 'slideId',
'route_param_field' => 'id_slide',
])
)
->add(
(new LinkRowAction('delete'))
->setName($this->trans('Delete', [], 'Admin.Actions'))
->setIcon('delete')
->setOptions([
'route' => 'is_imageslider_controller_delete',
'route_param_name' => 'slideId',
'route_param_field' => 'id_slide',
'confirm_message' => $this->trans(
'Delete selected item?',
[],
'Admin.Notifications.Warning'
),
])
),
])
);
}
/**
* {@inheritdoc}
*/
protected function getFilters()
{
return new FilterCollection();
}
/**
* {@inheritdoc}
*/
protected function getGridActions()
{
return new GridActionCollection();
}
/**
* {@inheritdoc}
*/
protected function getBulkActions()
{
return new BulkActionCollection();
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Grid\Query;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Adapter\Shop\Context;
use PrestaShop\PrestaShop\Core\Grid\Query\AbstractDoctrineQueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
final class ImageSliderQueryBuilder extends AbstractDoctrineQueryBuilder
{
/**
* @var Context
*/
private $shopContext;
private $contextLangId;
/**
* ImageSliderQueryBuilder constructor.
*
* @param Connection $connection
* @param $dbPrefix
* @param Context $shopContext
*/
public function __construct(Connection $connection, $dbPrefix, Context $shopContext, $contextLangId)
{
parent::__construct($connection, $dbPrefix);
$this->shopContext = $shopContext;
$this->contextLangId = $contextLangId;
}
/**
* @param SearchCriteriaInterface $searchCriteria
*
* @return QueryBuilder
*/
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
{
$qb = $this->getBaseQuery($searchCriteria->getFilters());
$qb->select('islide.id_slide, islidel.title, islidel.description, islidel.image, islide.active, islide.position')
->join('islide', $this->dbPrefix . 'image_slider_lang', 'islidel', 'islidel.id_slide = islide.id_slide')
->where('islidel.id_lang = :langId')
->setParameter('langId', (int) $this->contextLangId);
if (!$this->shopContext->isAllShopContext()) {
$qb->join('islide', $this->dbPrefix . 'image_slider_shop', 'islides', 'islides.id_slide = islide.id_slide')
->where('islides.id_shop in (' . implode(', ', $this->shopContext->getContextListShopID()) . ')')
->groupBy('islide.id_slide');
}
$qb->orderBy(
$searchCriteria->getOrderBy(),
$searchCriteria->getOrderWay()
)
->setFirstResult($searchCriteria->getOffset())
->setMaxResults($searchCriteria->getLimit());
$qb->orderBy('position');
return $qb;
}
/**
* @param SearchCriteriaInterface $searchCriteria
*
* @return QueryBuilder
*/
public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
{
$qb = $this->getBaseQuery();
$qb->select('COUNT(DISTINCT islide.id_slide)');
if (!$this->shopContext->isAllShopContext()) {
$qb->join('islide', $this->dbPrefix . 'image_slider_shop', 'islides', 'islides.id_slide = islide.id_slide')
->where('islides.id_shop in (' . implode(', ', $this->shopContext->getContextListShopID()) . ')');
}
return $qb;
}
/**
* @return QueryBuilder
*/
private function getBaseQuery(): QueryBuilder
{
return $this->connection
->createQueryBuilder()
->from($this->dbPrefix . 'image_slider', 'islide');
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Handler;
class FileEraser
{
private $targetDirectory;
public function __construct($targetDirectory)
{
$this->targetDirectory = $targetDirectory;
}
public function remove(string $fileName): bool
{
$result = true;
$fullFilePath = $this->targetDirectory . $fileName;
if (file_exists($fullFilePath)) {
$result = unlink($fullFilePath);
}
return $result;
}
public function getTargetDirectory()
{
return $this->targetDirectory;
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Handler;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileUploader
{
private $targetDirectory;
public function __construct($targetDirectory)
{
$this->targetDirectory = $targetDirectory;
}
public function upload(UploadedFile $file)
{
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$fileName = md5($originalFilename . time() . uniqid()) . '.' . $file->guessExtension();
$this->createUploadDirectoryIfNotExists();
try {
$file->move($this->getTargetDirectory(), $fileName);
} catch (FileException $e) {
}
return $fileName;
}
private function createUploadDirectoryIfNotExists()
{
if (!file_exists($this->getTargetDirectory())) {
mkdir($this->getTargetDirectory(), 0755, true);
}
}
public function getTargetDirectory()
{
return $this->targetDirectory;
}
}

View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
use Oksydan\IsImageslider\Cache\TemplateCache;
use Oksydan\IsImageslider\Configuration\SliderConfiguration;
use Oksydan\IsImageslider\Presenter\ImageSlidePresenter;
use Oksydan\IsImageslider\Repository\ImageSliderRepository;
abstract class AbstractCacheableDisplayHook extends AbstractDisplayHook
{
/**
* @var ImageSliderRepository
*/
protected $slideRepository;
/**
* @var ImageSlidePresenter
*/
protected $slidePresenter;
/**
* @var TemplateCache
*/
protected $templateCache;
public function __construct(
\Module $module,
\Context $context,
SliderConfiguration $sliderConfiguration,
ImageSliderRepository $slideRepository,
ImageSlidePresenter $slidePresenter,
TemplateCache $templateCache
) {
parent::__construct($module, $context, $sliderConfiguration);
$this->slideRepository = $slideRepository;
$this->slidePresenter = $slidePresenter;
$this->templateCache = $templateCache;
}
public function execute(array $params): string
{
if (!$this->shouldBlockBeDisplayed($params)) {
return '';
}
$this->templateCache->clearTemplateCacheIfNeeded($this->context->shop->id);
if (!$this->isTemplateCached()) {
$this->assignTemplateVariables($params);
}
return $this->module->fetch($this->getTemplateFullPath(), $this->getCacheKey());
}
protected function getCacheKey(): string
{
return $this->module->getCacheId();
}
protected function isTemplateCached(): bool
{
return $this->module->isCached($this->getTemplateFullPath(), $this->getCacheKey());
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
use Oksydan\IsImageslider\Configuration\SliderConfiguration;
abstract class AbstractDisplayHook extends AbstractHook
{
protected $sliderConfiguration;
public function __construct(
\Module $module,
\Context $context,
SliderConfiguration $sliderConfiguration
) {
parent::__construct($module, $context);
$this->sliderConfiguration = $sliderConfiguration;
}
public function execute(array $params): string
{
if (!$this->shouldBlockBeDisplayed($params)) {
return '';
}
$this->assignTemplateVariables($params);
return $this->module->fetch($this->getTemplateFullPath());
}
protected function assignTemplateVariables(array $params)
{
}
protected function shouldBlockBeDisplayed(array $params)
{
return true;
}
public function getTemplateFullPath(): string
{
return "module:{$this->module->name}/views/templates/hook/{$this->getTemplate()}";
}
abstract protected function getTemplate(): string;
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
abstract class AbstractHook implements HookInterface
{
protected $module;
protected $context;
public function __construct(\Module $module, \Context $context)
{
$this->module = $module;
$this->context = $context;
}
}

View File

@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
class DisplayHeader extends AbstractCacheableDisplayHook
{
private const TEMPLATE_FILE = 'head.tpl';
protected function getTemplate(): string
{
return DisplayHeader::TEMPLATE_FILE;
}
protected function assignTemplateVariables(array $params)
{
$slide = $this->getSlide();
$this->context->smarty->assign([
'image' => $slide['image_url'] ?? null,
]);
}
/**
* @return array
*/
private function getSlide(): array
{
$now = new \DateTime();
$slides = $this->slideRepository->getActiveSliderByLandAndStoreId(
$this->context->language->id,
$this->context->shop->id,
true,
1,
$now
);
foreach ($slides as &$slide) {
$slide = $this->slidePresenter->present($slide);
}
return count($slides) ? reset($slides) : [];
}
protected function getCacheKey(): string
{
return parent::getCacheKey() . '_' . ($this->context->isMobile() ? 'mobile' : 'desktop');
}
protected function shouldBlockBeDisplayed(array $params)
{
return $this->context->controller->getPageName() === 'index';
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
class DisplayHome extends AbstractCacheableDisplayHook
{
private const TEMPLATE_FILE = 'slider.tpl';
protected function getTemplate(): string
{
return DisplayHome::TEMPLATE_FILE;
}
protected function assignTemplateVariables(array $params)
{
$this->context->smarty->assign([
'homeslider' => [
'slides' => $this->getSlides(),
'speed' => $this->sliderConfiguration->getSliderSpeed(),
'pause' => $this->sliderConfiguration->getSliderPauseOnHover(),
'wrap' => $this->sliderConfiguration->getSliderWrap(),
],
]);
}
/**
* @return array
*/
private function getSlides(): array
{
$now = new \DateTime();
$slides = $this->slideRepository->getActiveSliderByLandAndStoreId(
$this->context->language->id,
$this->context->shop->id,
true,
0, // 0 means no limit
$now
);
foreach ($slides as &$slide) {
$slide = $this->slidePresenter->present($slide);
}
return $slides;
}
protected function getCacheKey(): string
{
return parent::getCacheKey() . '_' . ($this->context->isMobile() ? 'mobile' : 'desktop');
}
}

View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Hook;
interface HookInterface
{
public function execute(array $params);
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Oksydan\IsImageslider\Hook;
class WidgetCapability extends AbstractCacheableDisplayHook
{
private const TEMPLATE_FILE = 'slider.tpl';
protected function getTemplate(): string
{
return WidgetCapability::TEMPLATE_FILE;
}
protected function getCacheKey(): string
{
return parent::getCacheKey() . '_' . ($this->context->isMobile() ? 'mobile' : 'desktop');
}
/**
* @return array
*/
private function getSlides(): array
{
$now = new \DateTime();
$slides = $this->slideRepository->getActiveSliderByLandAndStoreId(
$this->context->language->id,
$this->context->shop->id,
true,
0, // 0 means no limit
$now
);
foreach ($slides as &$slide) {
$slide = $this->slidePresenter->present($slide);
}
return $slides;
}
public function getWidgetVariables($params): array
{
return [
'homeslider' => [
'slides' => $this->getSlides(),
'speed' => $this->sliderConfiguration->getSliderSpeed(),
'pause' => $this->sliderConfiguration->getSliderPauseOnHover(),
'wrap' => $this->sliderConfiguration->getSliderWrap(),
],
];
}
protected function assignTemplateVariables(array $params)
{
$this->context->smarty->assign($this->getWidgetVariables($params));
}
public function renderWidget($params): string
{
return $this->execute($params);
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Oksydan\IsImageslider\Installer;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Statement;
abstract class ActionDatabaseAbstract
{
public const HOOK_LIST = [];
/**
* @var Connection
*/
protected $connection;
/**
* @var string
*/
protected $dbPrefix;
/**
* @var array
*/
protected $queries = [];
/**
* @var array
*/
protected $tableData = [];
public function __construct(Connection $connection, string $dbPrefix)
{
$this->connection = $connection;
$this->dbPrefix = $dbPrefix;
}
public function execute(): bool
{
$result = true;
foreach ($this->getQueries() as $query) {
$statement = $this->connection->executeQuery($query);
if ($statement instanceof Statement && 0 !== (int) $statement->errorCode()) {
$result &= false;
}
}
return $result;
}
public function setData(array $data)
{
$this->tableData = $data;
return $this;
}
public function getData(): array
{
return $this->tableData;
}
public function getQueries(): array
{
return $this->queries;
}
public function setQueries($queries)
{
$this->queries = $queries;
return $this;
}
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
class ActionDatabaseAddColumn extends ActionDatabaseAbstract implements ActionDatabaseInterface
{
public function buildQuery(): void
{
$tablesArray = $this->tableData['database_add'] ?? [];
$this->setQueries([]);
$queriesArray = [];
foreach ($tablesArray as $tableName => $table) {
if (!empty($table['columns'])) {
foreach ($table['columns'] as $columnName => $columnDefinition) {
if (!$this->checkColumnExistenceInTable($tableName, $columnName)) {
$queriesArray[] = $this->buildSingleAddQuery($tableName, $columnName, $columnDefinition);
}
}
}
}
$this->setQueries($queriesArray);
}
private function buildSingleAddQuery($tableName, $columnName, $columnDefinition): string
{
$dbQuery = 'ALTER TABLE ' . $this->dbPrefix . $tableName . '
ADD ' . $columnName . ' ' . $columnDefinition;
return $dbQuery;
}
private function checkColumnExistenceInTable($tableName, $columnName): bool
{
$dbQuery = "SELECT count(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=DATABASE()
AND COLUMN_NAME='" . $columnName . "'
AND TABLE_NAME='" . $this->dbPrefix . $tableName . "'";
$statement = $this->connection->executeQuery($dbQuery);
return $statement->rowCount() > 0;
}
}

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
class ActionDatabaseCrateTable extends ActionDatabaseAbstract implements ActionDatabaseInterface
{
public const defaultEngine = 'InnoDb';
public const defaultCharset = 'UTF8';
public function buildQuery(): void
{
$tablesArray = $this->tableData['database'] ?? [];
$this->setQueries([]);
$queriesArray = [];
foreach ($tablesArray as $tableName => $table) {
$queriesArray[] = $this->buildSingleCreateQuery($tableName, $table);
}
$this->setQueries($queriesArray);
}
private function buildSingleCreateQuery($tableName, $table): string
{
$dbQuery = '';
if (empty($table['columns']) || empty($tableName)) {
return $dbQuery;
}
$dbQuery .= 'CREATE TABLE IF NOT EXISTS ' . $this->dbPrefix . $tableName;
$dbQuery .= ' (';
$dbColumnsQuery = [];
foreach ($table['columns'] as $columnName => $column) {
$dbColumnsQuery[] = $columnName . ' ' . $column;
}
if (!empty($table['primary'])) {
$dbColumnsQuery[] = 'PRIMARY KEY (' . implode(', ', $table['primary']) . ')';
}
$dbQuery .= implode(',', $dbColumnsQuery);
$dbQuery .= ')';
$dbQuery .= ' ENGINE = ' . (!empty($table['engine']) ? $table['engine'] : ActionDatabaseCrateTable::defaultEngine);
$dbQuery .= ' DEFAULT CHARACTER SET ' . (!empty($table['charset']) ? $table['charset'] : ActionDatabaseCrateTable::defaultCharset);
return $dbQuery;
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
class ActionDatabaseDropTable extends ActionDatabaseAbstract implements ActionDatabaseInterface
{
public function buildQuery(): void
{
$tablesArray = $this->tableData['database'] ?? [];
$this->setQueries([]);
$queriesArray = [];
foreach ($tablesArray as $tableName => $table) {
$queriesArray[] = $this->buildSingleDropQuery($tableName, $table);
}
$this->setQueries($queriesArray);
}
private function buildSingleDropQuery($tableName): string
{
$dbQuery = '';
if (empty($tableName)) {
return $dbQuery;
}
$dbQuery .= 'DROP TABLE IF EXISTS ' . $this->dbPrefix . $tableName;
return $dbQuery;
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
interface ActionDatabaseInterface
{
public function execute();
public function buildQuery();
public function setData(array $data);
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
class ActionDatabaseModifyColumn extends ActionDatabaseAbstract implements ActionDatabaseInterface
{
public function buildQuery(): void
{
$tablesArray = $this->tableData['database_modify'] ?? [];
$this->setQueries([]);
$queriesArray = [];
foreach ($tablesArray as $tableName => $table) {
if (!empty($table['columns'])) {
foreach ($table['columns'] as $columnName => $columnDefinition) {
if ($this->checkColumnExistenceInTable($tableName, $columnName)) {
$queriesArray[] = $this->buildSingleModifyQuery($tableName, $columnName, $columnDefinition);
}
}
}
}
$this->setQueries($queriesArray);
}
private function buildSingleModifyQuery($tableName, $columnName, $columnDefinition): string
{
$dbQuery = 'ALTER TABLE ' . $this->dbPrefix . $tableName . '
MODIFY COLUMN ' . $columnName . ' ' . $columnDefinition;
return $dbQuery;
}
private function checkColumnExistenceInTable($tableName, $columnName): bool
{
$dbQuery = "SELECT count(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=DATABASE()
AND COLUMN_NAME='" . $columnName . "'
AND TABLE_NAME='" . $this->dbPrefix . $tableName . "'";
$statement = $this->connection->executeQuery($dbQuery);
return $statement->rowCount() > 0;
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
use Symfony\Component\Yaml\Yaml;
class DatabaseYamlParser
{
/**
* @var DatabaseYamlProvider
*/
protected $yamlProvider;
/**
* @var array
*/
private $parsedFileData = [];
public function __construct($yamlProvider)
{
$this->yamlProvider = $yamlProvider;
}
public function getDatabaseYmlFilePath(): string
{
return $this->yamlProvider->getDatabaseFilePath();
}
private function parseFile(): void
{
$this->parsedFileData = Yaml::parseFile($this->getDatabaseYmlFilePath());
}
public function getParsedFileData(): array
{
if (empty($this->parsedFileData)) {
$this->parseFile();
}
return $this->parsedFileData;
}
}

View File

@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer;
use Doctrine\DBAL\Connection;
use PrestaShop\PrestaShop\Adapter\ContainerFinder;
class ImageSliderInstaller
{
/**
* @var DatabaseYamlParser
*/
private $databaseYaml;
/**
* @var Connection
*/
private $connection;
/**
* @var \Context
*/
private $context;
/**
* @param Connection $connection
* @param DatabaseYamlParser $databaseYaml
* @param \Context $context
*/
public function __construct(Connection $connection, DatabaseYamlParser $databaseYaml, $context)
{
$this->connection = $connection;
$this->databaseYaml = $databaseYaml;
$this->context = $context;
}
private function getContainer()
{
if (null === $this->context->container) {
$containerFinder = new ContainerFinder($this->context);
$container = $containerFinder->getContainer();
$this->context->container = $container;
}
return $this->context->container;
}
public function createTables(): bool
{
$databaseData = $this->databaseYaml->getParsedFileData();
$container = $this->getContainer();
// THIS WAY INSTEAD OF SERVICE CALL COZ OF NOT AVAILABLE SERVICE DURING INSTALLATION
$createTableAction = new ActionDatabaseCrateTable(
$container->get('doctrine.dbal.default_connection'),
$container->getParameter('database_prefix')
);
// THIS WAY INSTEAD OF SERVICE CALL COZ OF NOT AVAILABLE SERVICE DURING INSTALLATION
$addColumnsAction = new ActionDatabaseAddColumn(
$container->get('doctrine.dbal.default_connection'),
$container->getParameter('database_prefix')
);
// THIS WAY INSTEAD OF SERVICE CALL COZ OF NOT AVAILABLE SERVICE DURING INSTALLATION
$modifyColumnsAction = new ActionDatabaseModifyColumn(
$container->get('doctrine.dbal.default_connection'),
$container->getParameter('database_prefix')
);
$createTableAction
->setData($databaseData)
->buildQuery();
$addColumnsAction
->setData($databaseData)
->buildQuery();
$modifyColumnsAction
->setData($databaseData)
->buildQuery();
return $createTableAction->execute()
&& $addColumnsAction->execute()
&& $modifyColumnsAction->execute();
}
/**
* @return bool
*/
public function dropTables(): bool
{
$databaseData = $this->databaseYaml->getParsedFileData();
$container = $this->getContainer();
$dropTableAction = $container->get('oksydan.is_imageslider.installer.action_databse_drop_table');
$dropTableAction
->setData($databaseData)
->buildQuery();
$result = $dropTableAction->execute();
return $result;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Installer\Provider;
use Oksydan\IsImageslider\Exceptions\DatabaseYamlFileNotExistsException;
class DatabaseYamlProvider
{
/**
* @var \Is_imageslider
*/
protected $module;
public function __construct(\Is_imageslider $module)
{
$this->module = $module;
}
public function getDatabaseFilePath(): string
{
$filePossiblePath = _PS_MODULE_DIR_ . $this->module->name . '/config/';
$databaseFileName = 'database.yml';
$fullFilePath = $filePossiblePath . $databaseFileName;
if (file_exists($fullFilePath)) {
return $fullFilePath;
} else {
throw new DatabaseYamlFileNotExistsException($databaseFileName . ' file not eixtst in ' . $filePossiblePath);
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Presenter;
class ImageSlidePresenter
{
/**
* @var string
*/
private $imagesUri;
/**
* @var string
*/
private $imagesDir;
/**
* @var \Context
*/
private $context;
public function __construct(
string $imagesUri,
string $imagesDir,
\Context $context
) {
$this->imagesUri = $imagesUri;
$this->imagesDir = $imagesDir;
$this->context = $context;
}
public function present($slide): array
{
$imageField = $this->context->isMobile() ? 'imageMobile' : 'image';
$slide['image_url'] = $this->getImageUrl($slide[$imageField]);
$slide['sizes'] = $this->getImageSizes($slide[$imageField]);
return $slide;
}
private function getImageUrl($slideImage): string
{
return $this->context->link->getMediaLink($this->imagesUri . $slideImage);
}
private function getImageSizes($slideImage): array
{
$imageFullPath = $this->imagesDir . $slideImage;
$sizes = [];
if (file_exists($imageFullPath)) {
$sizes = getimagesize($imageFullPath);
}
return $sizes;
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Provider;
class ImageProvider implements ImageProviderInterface
{
/**
* @var string
*/
private $imagesUri;
public function __construct($imagesUri)
{
$this->imagesUri = $imagesUri;
}
/**
* {@inheritdoc}
*/
public function getPath(string $fileName): string
{
return $fileName ? $this->imagesUri . $fileName : '';
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Provider;
interface ImageProviderInterface
{
/**
* Get slider image path.
*
* @param string $fileName
*
* @return string Path to slider image
*/
public function getPath(string $fileName);
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Repository;
use Doctrine\DBAL\Connection;
/**
* Class HookModuleRepository is responsible for retrieving module data from database.
*/
class HookModuleRepository
{
/**
* @var Connection
*/
private $connection;
/**
* @var string
*/
private $databasePrefix;
/**
* @var string
*/
private $table;
/**
* @param Connection $connection
* @param string $databasePrefix
*/
public function __construct(Connection $connection, $databasePrefix)
{
$this->connection = $connection;
$this->databasePrefix = $databasePrefix;
$this->table = $this->databasePrefix . 'hook_module';
}
public function getAllHookRegisteredToModule($moduleId)
{
$qb = $this->connection->createQueryBuilder()
->select('h.name')
->from($this->table, 'mh')
->where('mh.id_module = :id_module')
->leftJoin('mh', $this->databasePrefix . 'hook', 'h', 'h.id_hook = mh.id_hook')
->setParameter('id_module', $moduleId);
return $qb->execute()->fetchAll();
}
}

View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Repository;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
class ImageSliderRepository extends EntityRepository
{
public function getAllIds(): array
{
/** @var QueryBuilder $qb */
$qb = $this
->createQueryBuilder('s')
->select('s.id')
;
$slides = $qb->getQuery()->getScalarResult();
return array_map(function ($slide) {
return $slide['id'];
}, $slides);
}
public function getHighestPosition(): int
{
$position = 0;
$qb = $this
->createQueryBuilder('s')
->select('s.position')
->orderBy('s.position', 'DESC')
->setMaxResults(1)
->getQuery();
$result = $qb->getOneOrNullResult();
if ($result) {
$position = $result['position'];
}
return $position;
}
private function addDateRangeFilter(QueryBuilder $qb, \DateTime $date): QueryBuilder
{
$qb
->andWhere('s.display_from <= :from')
->andWhere('s.display_to >= :to')
->setParameter('from', $date->format('Y-m-d H:i:s'))
->setParameter('to', $date->format('Y-m-d H:i:s'))
;
return $qb;
}
public function getSimpleActiveSliderByStoreId(
int $idStore,
bool $activeOnly = true,
int $limit = 0,
\DateTime $date = null
): array {
$qb = $this
->createQueryBuilder('s')
->select('s.id, s.position, s.active, s.display_from, s.display_to')
->join('s.shops', 'ss')
->andWhere('ss.id = :storeId')
->orderBy('s.position')
->setParameter('storeId', (int) $idStore);
if ($activeOnly) {
$qb->andWhere('s.active = 1');
}
if ($limit) {
$qb->setMaxResults($limit);
}
if ($date) {
$qb = $this->addDateRangeFilter($qb, $date);
}
return $qb->getQuery()->getScalarResult();
}
public function getActiveSliderByLandAndStoreId(
int $idLang,
int $idStore,
bool $activeOnly = true,
int $limit = 0,
\DateTime $date = null
): array {
$qb = $this
->createQueryBuilder('s')
->select('sl.title, sl.legend, sl.url, sl.description, sl.image, sl.imageMobile, s.display_from, s.display_to')
->join('s.sliderLangs', 'sl')
->join('s.shops', 'ss')
->andWhere('sl.lang = :langId')
->andWhere('ss.id = :storeId')
->orderBy('s.position')
->setParameter('langId', (int) $idLang)
->setParameter('storeId', (int) $idStore);
if ($activeOnly) {
$qb->andWhere('s.active = 1');
}
if ($limit) {
$qb->setMaxResults($limit);
}
if ($date) {
$qb = $this->addDateRangeFilter($qb, $date);
}
return $qb->getQuery()->getScalarResult();
}
}

View File

@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Translations;
class TranslationDomains
{
public const TRANSLATION_DOMAIN_ADMIN = 'Modules.Isimageslider.Admin';
public const TRANSLATION_DOMAIN_FRONT = 'Modules.Isimageslider.Front';
public const TRANSLATION_DOMAIN_EXCEPTION = 'Modules.Isimageslider.Exceptions';
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Oksydan\IsImageslider\Type;
use PrestaShopBundle\Form\Admin\Type\TranslatableType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TranslatableFile extends TranslatableType
{
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
parent::buildView($view, $form, $options);
$view->vars = array_replace($view->vars, [
'locales' => $options['locales'],
'default_locale' => reset($options['locales']),
]);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'choice_translation_domain' => false,
'allow_extra_fields' => true,
]);
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'translatable_file';
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;