* @copyright 2024 Anvanto * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ if (!defined('_PS_VERSION_')) { exit; } use PrestaShop\PrestaShop\Adapter\Image\ImageRetriever; use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter; use PrestaShop\PrestaShop\Core\Product\ProductListingPresenter; use PrestaShop\PrestaShop\Adapter\Product\ProductColorsRetriever; // Featured use PrestaShop\PrestaShop\Adapter\Category\CategoryProductSearchProvider; // PricesDrop use PrestaShop\PrestaShop\Adapter\PricesDrop\PricesDropProductSearchProvider; // BestSellers use PrestaShop\PrestaShop\Adapter\BestSales\BestSalesProductSearchProvider; // New use PrestaShop\PrestaShop\Adapter\NewProducts\NewProductsProductSearchProvider; use PrestaShop\PrestaShop\Core\Product\Search\ProductSearchContext; use PrestaShop\PrestaShop\Core\Product\Search\ProductSearchQuery; use PrestaShop\PrestaShop\Core\Product\Search\SortOrder; require_once _PS_MODULE_DIR_ . 'an_homeproducts/classes/anHomeProductFiles.php'; class anHomeProductsBlocks extends ObjectModel { /** * @var int */ public $id_block; /** * @var int */ public $id; public $special_id_block; public $type = 'new-products'; public $active = 1; public $show_sort = 0; public $show_sub_cat = 0; public $products_display = 8; public $id_category = 0; public $position; public $title; public $text; public $link; /** * @var array */ public static $definition = [ 'table' => 'an_homeproducts_blocks', 'primary' => 'id_block', 'multilang' => true, 'fields' => [ 'special_id_block' => ['type' =>self::TYPE_STRING ], 'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'show_sort' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'products_display' => ['type' =>self::TYPE_INT ], 'id_category' => ['type' =>self::TYPE_INT ], 'show_sub_cat' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'position' => ['type' =>self::TYPE_INT ], 'type' => ['type' =>self::TYPE_STRING ], 'title' => ['type' =>self::TYPE_STRING,'lang' => true, 'validate' => 'isString', 'required' => true, 'size' => 256 ], 'text' => ['type' =>self::TYPE_HTML,'lang' => true ], 'link' => ['type' =>self::TYPE_STRING,'lang' => true ] ], ]; public function __construct($id = null, $id_lang = null) { parent::__construct($id, $id_lang); } public function add($auto_date = true, $null_values = false) { if (empty($this->special_id_block)) { $this->special_id_block = uniqid(); } return parent::add($auto_date, $null_values); } public function getData($params = []) { $context = Context::getContext(); $data = self::getBlockData((array) $this, $params); $this->sort = $data['sort']; $this->products = $data['products']; $this->totalProducts = $data['totalProducts']; $this->productsNextPage = $data['productsNextPage']; if ($this->id_category){ $this->childrenCats = Category::getChildren( $this->id_category, $context->language->id, true, $context->shop->id ); } } public static function getBlockData($block, $params = []) { switch ($block['type']){ case 'new-products': return self::getNewProducts($block['products_display'], $params); break; case 'best-sales': return self::getBestSellers($block['products_display'], $params); break; case 'prices-drop': return self::getSpecials($block['products_display'], $params); break; case 'prices-drop-percentage': return self::getSpecialsPercentage($block['products_display'], $params); break; case 'category': return self::getProductsCategory($block, $params); break; case 'categories': return self::getProductsCategories($block, $params); break; case 'products': return self::getProductsByIds($block, $params); break; } } public static function getBlocks($mergeData = true, $all = false) { $sql = ' SELECT * FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks` sw LEFT JOIN `' . _DB_PREFIX_ . 'an_homeproducts_blocks_lang` sl ON (sw.`id_block` = sl.`id_block` AND sl.`id_lang` = ' . (int) Context::getContext()->language->id . ') '; if (!$all){ $sql .= 'WHERE sw.`active`=1 '; } if (Shop::isFeatureActive()) { $sql .= ' AND sw.`id_block` IN ( SELECT sa.`id_block` FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_shop` sa WHERE sa.id_shop IN (' . implode(', ', Shop::getContextListShopID()) . ') )'; } $sql .= ' ORDER BY sw.`position`'; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); foreach ($result as $key => $field){ $sql_lang = 'SELECT * FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_lang` WHERE `id_block` = ' . (int) $field['id_block'] . ''; $res_lang = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql_lang); $langContent = []; foreach ($res_lang as $item){ $item['iso_code'] = Language::getIsoById($item['id_lang']); $langContent[$item['iso_code']] = $item; } $result[$key]['languages'] = $langContent; } if ($mergeData){ foreach ($result as $id => $block){ $result[$id] = array_merge($result[$id], (array) self::getBlockData($block)); } } if (!$result) { return []; } else { return $result; } } public static function getProductsCategory($block, $params = []) { $context = Context::getContext(); $nProducts = $block['products_display']; if (!isset($params['sort']) || $params['sort'] == ''){ $params['sort'] = 'product.position.asc'; } $page = 1; if (isset($params['page']) && $params['page'] > 0){ $page = intval($params['page']); } $childrenCats = Category::getChildren( $block['id_category'], $context->language->id, true, $context->shop->id ); $return['childrenCats'] = $childrenCats; if (isset($params['idCategory']) && $params['idCategory']){ $category = new Category((int) $params['idCategory']); } else { $category = new Category((int) $block['id_category']); } $searchProvider = new CategoryProductSearchProvider( $context->getTranslator(), $category ); $contextSearch = new ProductSearchContext($context); $query = new ProductSearchQuery(); $query ->setResultsPerPage($nProducts) ->setPage($page) ; $query->setSortOrder(SortOrder::newFromString( $params['sort'] )); $result = $searchProvider->runQuery( $contextSearch, $query ); $products = $result->getProducts(); $availableSort = []; foreach ($result->getAvailableSortOrders() as $itemSort){ $availableSort[] = $itemSort->toArray(); } $return['sort'] = $availableSort; $return['products'] = self::productsPrepareForTemplate($context, $products); $return['totalProducts'] = $result->getTotalProductsCount(); $return['productsNextPage'] = $return['totalProducts'] - ($page * $nProducts); if ($return['productsNextPage'] < 0) { $return['productsNextPage'] = 0; } return $return; // return self::productsPrepareForTemplate($context, $products); } public static function getProductsByIds($block, $params = []) { $nProducts = $block['products_display']; $id_block = $block['id_block']; $randomize = false; $context = Context::getContext(); $langId = Context::getContext()->language->id; $sql = ' SELECT *, p.* FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_products` awl LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON (p.`id_product` = awl.`id_product`) LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = ' . (int) $langId . Shop::addSqlRestrictionOnLang('pl') . ') WHERE awl.`id_block` = ' . (int) $id_block . ' ORDER BY awl.`position` LIMIT 0,'.(int) $nProducts.' '; $products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql, true, false); if (!$products){ $products = []; } $return['sort'] = []; $return['products'] = self::productsPrepareForTemplate($context, $products); $return['totalProducts'] = 0; $return['productsNextPage'] = 0; return $return; } public static function getProductsCategories($block, $params = []) { $randomize = false; $context = Context::getContext(); $nProducts = $block['products_display']; $cats = self::getBlockCategories($block['id_block']); $query = new ProductSearchQuery(); if ($randomize) { $query->setSortOrder(SortOrder::random()); } else { $query->setSortOrder(new SortOrder('product', 'position', 'asc')); } $products = []; while (count($products) < $nProducts && count($cats)){ foreach ($cats as $id => $categoryId){ $page = 1; while ($page){ $query ->setResultsPerPage($nProducts) ->setPage($page) ; $category = new Category((int) $categoryId); $searchProvider = new CategoryProductSearchProvider( $context->getTranslator(), $category ); $result = $searchProvider->runQuery( new ProductSearchContext($context), $query ); $productsCat = $result->getProducts(); if (count($productsCat) == 0){ unset($cats[$id]); break; } $products = array_merge($products, $productsCat); if (count($products) >= $nProducts){ break; } $page++; } } } // shuffle($products); $products = array_chunk($products, $nProducts, true); $products = array_shift($products); $return['sort'] = []; $return['products'] = self::productsPrepareForTemplate($context, $products); $return['totalProducts'] = 0; $return['productsNextPage'] = 0; return $return; // return self::productsPrepareForTemplate($context, $products); } public static function getBlockCategories($idBlock) { if (!$idBlock){ return []; } $sql = 'SELECT `id_category` FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_categories` WHERE `id_block` = ' . (int) $idBlock . ' '; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql, true, false); $cats = []; if ($result) { foreach ($result as $item){ $cats[] = $item['id_category']; } } return $cats; } public static function getBestSellers($nProducts = 8, $params = []) { if (Configuration::get('PS_CATALOG_MODE')) { return false; } $context = Context::getContext(); if (!isset($params['sort']) || $params['sort'] == ''){ $params['sort'] = 'product.name.asc'; } $page = 1; if (isset($params['page']) && $params['page'] > 0){ $page = intval($params['page']); } $contextSearch = new ProductSearchContext($context); $query = new ProductSearchQuery(); $query ->setResultsPerPage($nProducts) ->setPage($page) ; $query->setQueryType('best-sales'); $query->setSortOrder(SortOrder::newFromString( $params['sort'] )); $searchProvider = new BestSalesProductSearchProvider( $context->getTranslator() ); $result = $searchProvider->runQuery( $contextSearch, $query ); $products = $result->getProducts(); $availableSort = []; foreach ($result->getAvailableSortOrders() as $itemSort){ $availableSort[] = $itemSort->toArray(); } $return['sort'] = $availableSort; $return['products'] = self::productsPrepareForTemplate($context, $products); $return['totalProducts'] = $result->getTotalProductsCount(); $return['productsNextPage'] = $return['totalProducts'] - ($page * $nProducts); if ($return['productsNextPage'] < 0) { $return['productsNextPage'] = 0; } return $return; // return self::productsPrepareForTemplate($context, $products); } public static function getNewProducts($nProducts = 8, $params = []) { $context = Context::getContext(); if (!isset($params['sort']) || $params['sort'] == ''){ $params['sort'] = 'product.date_add.desc'; } $page = 1; if (isset($params['page']) && $params['page'] > 0){ $page = intval($params['page']); } $searchProvider = new NewProductsProductSearchProvider( $context->getTranslator() ); $contextSearch = new ProductSearchContext($context); $query = new ProductSearchQuery(); $query ->setResultsPerPage($nProducts) ->setPage($page) ; $query->setQueryType('new-products'); $query->setSortOrder(SortOrder::newFromString( $params['sort'] )); $result = $searchProvider->runQuery( $contextSearch, $query ); // totalProductsCount availableSortOrders currentSortOrder //echo '
'; var_dump($result); die;

        //  $result->getAvailableSortOrders()['0']->getLabel() - доступные методы сортировки для блока


       // echo '
'; var_dump($result->getCurrentSortOrder()); die;

        $products = $result->getProducts();

        $availableSort = [];
        foreach ($result->getAvailableSortOrders() as $itemSort){
            $availableSort[] = $itemSort->toArray();
        }
        $return['sort'] = $availableSort;

        $return['products'] = self::productsPrepareForTemplate($context, $products);
        $return['totalProducts'] = $result->getTotalProductsCount();
        $return['productsNextPage'] = $return['totalProducts'] - ($page * $nProducts);
        if ($return['productsNextPage'] < 0) {
            $return['productsNextPage'] = 0;
        }
        return $return;


//        return self::productsPrepareForTemplate($context, $products);
    }

    public static function getSpecials($nProducts = 8, $params = [])
    {
        $context = Context::getContext();

        if (!isset($params['sort']) || $params['sort'] == ''){
            $params['sort'] = 'product.name.asc';
        }

        $page = 1;
        if (isset($params['page']) && $params['page'] > 0){
            $page = intval($params['page']);
        }

        $searchProvider = new PricesDropProductSearchProvider(
            $context->getTranslator()
        );

        $contextSearch = new ProductSearchContext($context);

        $query = new ProductSearchQuery();
        $query
            ->setResultsPerPage($nProducts)
            ->setPage($page)
        ;
        $query->setQueryType('prices-drop');
        $query->setSortOrder(SortOrder::newFromString(
            $params['sort']
        ));

        $result = $searchProvider->runQuery(
            $contextSearch,
            $query
        );

        $products = $result->getProducts();

        $availableSort = [];
        foreach ($result->getAvailableSortOrders() as $itemSort){
            $availableSort[] = $itemSort->toArray();
        }
        $return['sort'] = $availableSort;

        $return['products'] = self::productsPrepareForTemplate($context, $products);
        $return['totalProducts'] = $result->getTotalProductsCount();
        $return['productsNextPage'] = $return['totalProducts'] - ($page * $nProducts);
        if ($return['productsNextPage'] < 0) {
            $return['productsNextPage'] = 0;
        }
        return $return;

    //    return self::productsPrepareForTemplate($context, $products);
    }

    public static function getSpecialsPercentage($nProducts = 8, $params = [])
    {
        $page = 1;
        if (isset($params['page']) && $params['page'] > 0){
            $page = intval($params['page']);
        }
        $context = Context::getContext();
        $id_lang = $context->language->id;
        $front = true;
        $sql = '
        SELECT
            p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`,
            IFNULL(product_attribute_shop.id_product_attribute, 0) id_product_attribute,
            pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`,
            pl.`name`, image_shop.`id_image` id_image, il.`legend`, m.`name` AS manufacturer_name,
            DATEDIFF(
                p.`date_add`,
                DATE_SUB(
                    "' . date('Y-m-d') . ' 00:00:00",
                    INTERVAL ' . (Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20) . ' DAY
                )
            ) > 0 AS new
        FROM `' . _DB_PREFIX_ . 'specific_price` sprc, `' . _DB_PREFIX_ . 'product` p
            ' . Shop::addSqlAssociation('product', 'p') . '
            LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute_shop` product_attribute_shop
                ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop=' . (int) $context->shop->id . ')
            ' . Product::sqlStock('p', 0, false, $context->shop) . '
            LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (
                p.`id_product` = pl.`id_product`
                AND pl.`id_lang` = ' . (int) $id_lang . Shop::addSqlRestrictionOnLang('pl') . '
            )
            LEFT JOIN `' . _DB_PREFIX_ . 'image_shop` image_shop
                ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop=' . (int) $context->shop->id . ')
            LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ')
            LEFT JOIN `' . _DB_PREFIX_ . 'manufacturer` m ON (m.`id_manufacturer` = p.`id_manufacturer`)
        WHERE product_shop.`active` = 1
        AND p.id_product = sprc.id_product
        AND sprc.reduction_type = "percentage"
        AND product_shop.`show_price` = 1
        ' . ($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') . '
        ';
        $sql .= '
            ORDER BY sprc.reduction DESC
            LIMIT ' . (int) (($page - 1) * $nProducts) . ', ' . (int) $nProducts;
        $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);

        if (!$result) {
            return false;
        }
        $products = Product::getProductsProperties($id_lang, $result);
        $return['products'] = self::productsPrepareForTemplate($context, $products);;
    //    $return['totalProducts'] = $result->getTotalProductsCount();
    //    $return['productsNextPage'] = $return['totalProducts'] - ($page * $nProducts);
        $return['productsNextPage'] = 0;
        if ($return['productsNextPage'] < 0) {
            $return['productsNextPage'] = 0;
        }
        return $return;
    }

    public static function productsPrepareForTemplate($context, $products)
    {
        $assembler = new ProductAssembler($context);

        $presenterFactory = new ProductPresenterFactory($context);
        $presentationSettings = $presenterFactory->getPresentationSettings();
        $presenter = $presenterFactory->getPresenter();

        $products_for_template = [];

        if (is_array($products)) {
            foreach ($products as $rawProduct) {
                $products_for_template[] = $presenter->present(
                    $presentationSettings,
                    $assembler->assembleProduct($rawProduct),
                    $context->language
                );
            }
        }

        return $products_for_template;
    }

    public static function getProducsByIdBlock($id_block)
    {
        if (!$id_block){
            return [];
        }

        $langId = Context::getContext()->language->id;

        $sql = '
        SELECT  *, p.*
        FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_products` awl

        LEFT JOIN `' . _DB_PREFIX_ . 'product` p
            ON (p.`id_product` = awl.`id_product`)

        LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl
            ON (p.`id_product` = pl.`id_product`
            AND pl.`id_lang` = ' . (int) $langId . Shop::addSqlRestrictionOnLang('pl') . ')

        WHERE awl.`id_block` = ' . (int) $id_block . '
        ORDER BY awl.`position`';

        $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql, true, false);

        return Product::getProductsProperties($langId, $result);
    }












    public static function exportJsonBlocks($filesManager)
    {
        $blocks = self::getBlocks(false, true);
        @file_put_contents($filesManager->getJsonDirblocks(), json_encode($blocks, JSON_PRETTY_PRINT));
    }

    public static function importJsonBlocks($filesManager)
    {
        $data = json_decode($filesManager->getJsonBlocksPathFile(), true);
        $languages = Language::getLanguages();

        if ($data){

            foreach ($data as $item){

                $blockObj = new anHomeProductsBlocks();
                $blockObj->special_id_block = $item['special_id_block'];
                $blockObj->active = $item['active'];
                $blockObj->show_sort = $item['show_sort'];
                $blockObj->products_display = $item['products_display'];
                $blockObj->id_category = $item['id_category'];
                $blockObj->show_sub_cat = $item['show_sub_cat'];
                $blockObj->position = $item['position'];
                $blockObj->type = $item['type'];

                if (isset($item['languages']) && is_array($item['languages'])) {
                    foreach ($item['languages'] as $key => $field) {
                        $langId = Language::getIdByIso($field['iso_code']);
                        $blockObj->title[$langId] = $field['title'];
                        $blockObj->text[$langId] = $field['text'];
                        $blockObj->link[$langId] = $field['link'];
                    }
                }

                foreach ($languages as $language) {

                    if (!isset($blockObj->title[$language['id_lang']])){
                        $blockObj->title[$language['id_lang']] = $item['title'];
                    }

                    if (!isset($blockObj->text[$language['id_lang']])){
                        $blockObj->text[$language['id_lang']] = $item['text'];
                    }

                    if (!isset($blockObj->link[$language['id_lang']])){
                        $blockObj->link[$language['id_lang']] = $item['link'];
                    }
                }

                $blockObj->save();

                Db::getInstance()->insert('an_homeproducts_blocks_shop', [
                    'id_block' => (int) $blockObj->id,
                    'id_shop' => (int) Context::getContext()->shop->id
                ]);
            }
        }
    }

    public static function getCountBlocks()
    {
        $sql = '
        SELECT count(*) FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks` sw
        LEFT JOIN `' . _DB_PREFIX_ . 'an_homeproducts_blocks_lang` sl
            ON (sw.`id_block` = sl.`id_block`
            AND sl.`id_lang` = ' . (int) Context::getContext()->language->id . ')
        ';

        if (Shop::isFeatureActive()) {
            $sql .= ' WHERE sw.`id_block` IN (
                SELECT sa.`id_block`
                FROM `' . _DB_PREFIX_ . 'an_homeproducts_blocks_shop` sa
                WHERE sa.id_shop IN (' . implode(', ', Shop::getContextListShopID()) . ')
            )';
        }

        return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
    }



}