HEX
Server: Apache/2.4.6 (CentOS) mpm-itk/2.4.7-04 mod_fcgid/2.3.9 PHP/5.4.16
System: Linux dvm.vladweb.ru 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
User: region-gk.ru (1016)
PHP: 7.3.33
Disabled: NONE
Upload Files
File: //home/bk/salut/primsalut.ru/view/ProductsView.php
<?php

require_once('View.php');

class ProductsView extends View {

    // ЧПУ
    private $meta_array = array();
    private $set_canonical = false;
    private $meta = array('h1'=>'','title'=>'','keywords'=>'','description'=>'');
    private $meta_delimiter = ', ';
    private $subdir = '';
    private $lang_label = '';
    private $catalog_type = '';
    private $uri_array = array();
    private $is_wrong_params = 0;
    private $features_urls = array();
    private $category_brands = array();
    private $max_filter_brands = 1;
    private $max_filter_options = 1;
    private $max_filter_features = 2;
        
    public function __construct() {
        parent::__construct();
        $this->lang_label = $this->language->label;
        if (strlen($this->config->subfolder) > 1) {
            $this->subdir = "/?".$this->config->subfolder;
        }
        $translations = $this->translations->get_translations(array('lang'=>$this->language->label));

        /**
         *
         * внешний вид параметров:
         * brand-brandUrl1_brandUrl2... - фильтр по брендам
         * paramUrl-paramValue1_paramValue2... - фильтр по мультисвойствам
         * page-pageNumber - постраничная навигация
         * sort-sortParam - параметры сортировки
         *
         */
        
        //определение текущего положения и выставленных параметров
        $this->uri_array = $this->filter_chpu_parse_url();
        foreach($this->uri_array as $k=>$v) {
            if(empty($v)) {
                continue;
            }
            if(!$k && $brand=$this->brands->get_brand((string)$v)) {
                //$_GET['brand'] = $brand->url;
                $this->is_wrong_params = 1;
            } else {
                @list($param_name, $param_values) = explode('-',$v);
                if (in_array($this->page->url, array('all-products', 'discounted', 'bestsellers'))
                        && !in_array($param_name, array('page', 'sort'))) {
                    $this->is_wrong_params = 1;
                    break;
                }
                switch($param_name) {
                    case 'brand': {
                        $_GET['b'] = array();
                        foreach(explode('_',$param_values) as $bv) {
                            if(($brand = $this->brands->get_brand((string)$bv)) && !in_array($brand->id, $_GET['b'])) {
                                $_GET['b'][] = $brand->id;
                                $this->meta_array['brand'][] = $translations->products_brand.' '. $brand->name;
                            } else {
                                $this->is_wrong_params = 1;
                            }
                        }
                        break;
                    }
                    case 'page': {
                        $_GET['page'] = $param_values;
                        if ($param_values != 'all' && (!preg_match('~^[0-9]+$~', $param_values) || strpos($param_values, '0') === 0)) {
                            $this->is_wrong_params = 1;
                        }
                        break;
                    }
                    case 'sort': {
                        $_GET['sort'] = strval($param_values);
                        if (!in_array($_GET['sort'], array('position', 'price', 'price_desc', 'name', 'name_desc', 'rating', 'rating_desc'))) {
                            $this->is_wrong_params = 1;
                        }
                        break;
                    }
                    default: {
                        if(($feature = $this->features->get_feature($param_name)) && !isset($_GET[$feature->id])) {
                            $_GET[$feature->id] = explode('_',$param_values);
                            // если нет повторяющихся значений свойства - ок, иначе 404
                            if (count($_GET[$feature->id]) == count(array_unique($_GET[$feature->id]))) {
                                $option_translits = array();
                                foreach ($this->features->get_options(array('feature_id' => $feature->id)) as $fo) {
                                    $option_translits[] = $fo->translit;
                                    if (in_array($fo->translit, $_GET[$feature->id])) {
                                        $this->meta_array['options'][$feature->id][] = $fo->value;
                                    }
                                }
                                foreach ($_GET[$feature->id] as $param_value) {
                                    if (!in_array($param_value, $option_translits)) {
                                        $this->is_wrong_params = 1;
                                        break;
                                    }
                                }
                            } else {
                                $this->is_wrong_params = 1;
                            }
                        } else {
                            $this->is_wrong_params = 1;
                        }
                    }
                }
            }
        }
        
        if(!empty($this->meta_array)) {
            foreach($this->meta_array as $type=>$_meta_array) {
                switch($type) {
                    case 'brand': {
                        if(count($_meta_array) > $this->max_filter_brands) {
                            $this->set_canonical = true;
                        }
                        $this->meta['h1'] = $this->meta['title'] = $this->meta['keywords'] = $this->meta['description'] = implode($this->meta_delimiter,$_meta_array);
                        break;
                    }
                    case 'options': {
                        foreach($_meta_array as $f_id=>$f_array) {
                            if(count($f_array) > $this->max_filter_options || count($_meta_array) > $this->max_filter_features) {
                                $this->set_canonical = true;
                            }
                            $this->meta['h1']           .= (!empty($this->meta['h1'])           ? $this->meta_delimiter : '') . implode($this->meta_delimiter,$f_array);
                            $this->meta['title']        .= (!empty($this->meta['title'])        ? $this->meta_delimiter : '') . implode($this->meta_delimiter,$f_array);
                            $this->meta['keywords']     .= (!empty($this->meta['keywords'])     ? $this->meta_delimiter : '') . implode($this->meta_delimiter,$f_array);
                            $this->meta['description']  .= (!empty($this->meta['description'])  ? $this->meta_delimiter : '') . implode($this->meta_delimiter,$f_array);
                        }
                        break;
                    }
                }
            }
        }
        
        if(!empty($this->meta['h1'])) {
            $this->meta['h1']           = !empty($translations->ceo_filter_s_harakteristikami) ? ' ' : ''.$translations->ceo_filter_s_harakteristikami.' '.$this->meta['h1'];
        }
        if(!empty($this->meta['title'])) {
            $this->meta['title']        = !empty($translations->ceo_filter_s_harakteristikami) ? ' ' : ''.$translations->ceo_filter_s_harakteristikami.' '.$this->meta['title'];
        }
        if(!empty($this->meta['keywords'])) {
            $this->meta['keywords']     = !empty($translations->ceo_filter_s_harakteristikami) ? ' ' : ''.$translations->ceo_filter_s_harakteristikami.' '.$this->meta['keywords'];
        }
        if(!empty($this->meta['description'])) {
            $this->meta['description']  = !empty($translations->ceo_filter_s_harakteristikami) ? ' ' : ''.$translations->ceo_filter_s_harakteristikami.' '.$this->meta['description'];
        }
        
        if($this->set_canonical) {
            $this->meta['h1'] = $this->meta['title'] = $this->meta['keywords'] = $this->meta['description'] = '';
        }
        
        $this->design->assign('set_canonical',$this->set_canonical);
        $this->design->assign('filter_meta',(object)$this->meta);
        $this->design->assign('show_alternate', empty($this->meta_array['options']));
        if (empty($this->meta_array)) {
            $this->design->assign('self_canonical', true);
        }
        
        $this->design->smarty->registerPlugin('function', 'furl', array($this, 'filter_chpu_url'));
    }

    public function filter_chpu_url($params, &$smarty) {
        if(is_array(reset($params))) {
            $params = reset($params);
        }

        $result_array = array('brand'=>array(),'features'=>array(),'sort'=>null,'page'=>null);
        //Определяем, что у нас уже есть в строке
        foreach($this->uri_array as $k=>$v) {
            if($k>0 || !($brand=$this->brands->get_brand((string)$v))) {
                list($param_name, $param_values) = explode('-',$v);
                switch($param_name) {
                    case 'brand': {
                        $result_array['brand'] = explode('_',$param_values);
                        break;
                    }
                    case 'sort': {
                        $result_array['sort'] = strval($param_values);
                        break;
                    }
                    case 'page': {
                        $result_array['page'] = $param_values;
                        break;
                    }
                    default: {
                        $result_array['features'][$param_name] = explode('_',$param_values);
                    }
                }
            }
        }
        //Определяем переданные параметры для ссылки
        foreach($params as $k=>$v) {
            switch($k) {
                case 'brand': {
                    if(is_null($v)) {
                        unset($result_array['brand']);
                    } elseif(in_array($v,$result_array['brand'])) {
                        unset($result_array['brand'][array_search($v,$result_array['brand'])]);
                    } else {
                        $result_array['brand'][] = $v;
                    }
                    break;
                }
                case 'sort':
                    $result_array['sort'] = strval($v);
                    break;
                case 'page':
                    $result_array['page'] = $v;
                    break;
                default:
                    if(is_null($v)) {
                        unset($result_array['features'][$k]);
                    } elseif(!empty($result_array['features']) && in_array($k,array_keys($result_array['features'])) && in_array($v,$result_array['features'][$k])) {
                        unset($result_array['features'][$k][array_search($v,$result_array['features'][$k])]);
                    } else {
                        $result_array['features'][$k][] = $v;
                    }
                    if(empty($result_array['features'][$k])) {
                        unset($result_array['features'][$k]);
                    }
                break;
            }
        }
        //формируем ссылку
        if (strlen($this->config->subfolder) > 1) {
            $result_string = '/'.$this->config->subfolder.$this->lang_link.$this->catalog_type;
        } else {
            $result_string = '/'.$this->lang_link.$this->catalog_type;
        }
        if(!empty($_GET['category'])) {
            $result_string .= '/' . $_GET['category'];
        }
        if(!empty($_GET['brand'])) {
            $result_string .= '/' . $_GET['brand'];
        }

        $link_tag = "a";
        if(!empty($result_array['brand'])) {
            if (count($result_array['brand']) > $this->max_filter_brands) {
                $link_tag = "span";
            }
            $result_string .= '/brand-' . implode('_',$this->filter_chpu_sort_brands($result_array['brand'])); // - это с сортировкой по брендам
            //$result_string .= '/brand-' . implode('_',$result_array['brand']); // - это без сортировки по брендам
        }
        foreach($result_array['features'] as $k=>$v) {
            if (count($result_array['features'][$k]) > $this->max_filter_options || count($result_array['features']) > $this->max_filter_features) {
                $link_tag = "span";
            }
        }
        if(!empty($result_array['features'])) {
            $result_string .= $this->filter_chpu_sort_features($result_array['features']);
        }
        if(!empty($result_array['sort'])) {
            $result_string .= '/sort-' . $result_array['sort'];
        }
        if($result_array['page'] > 1 || $result_array['page'] == 'all') {
            $result_string .= '/page-' . $result_array['page'];
        }
        $keyword = $this->request->get('keyword');
        if (!empty($keyword)) {
            $result_string .= '?keyword='.$keyword;
        }
        $smarty->assign('link_tag', $link_tag);
        //отдаем сформированную ссылку
        return $result_string;
    }

    private function filter_chpu_sort_brands($brands_urls = array()) {
        if(empty($brands_urls)) {
            return false;
        }
        $result = array();
        foreach ($this->category_brands as $b) {
            if (in_array($b->url, $brands_urls)) {
                $result[] = $b->url;
            }
        }
        return $result;
    }

    private function filter_chpu_sort_features($features = array()) {
        if(empty($features)) {
            return false;
        }
        $result_string = '';
        foreach ($this->features_urls as $furl) {
            if (in_array($furl, array_keys($features))) {
                $result_string .= '/'.$furl.'-'.implode('_', $features[$furl]);
            }
        }
        return $result_string;
    }

    private function filter_chpu_parse_url() {
        $uri = @parse_url($_SERVER["REQUEST_URI"]);
        preg_match("~^$this->subdir(/?$this->lang_label)?/?(catalog|all-products|brands|discounted|bestsellers)/?~", $uri['path'], $this->catalog_type);
        $this->catalog_type = $this->catalog_type[2];
        //убираем модификатор каталога
        $uri = preg_replace("~^$this->subdir(/?$this->lang_label)?/?(catalog|all-products|brands|discounted|bestsellers)/?~",'',$uri['path']);
        $this->uri_array = (empty($uri) ? array() : explode('/',$uri));
        if ($this->catalog_type == 'catalog' || $this->catalog_type == 'brands') {
            array_shift($this->uri_array);
        }
        return $this->uri_array;
    }
    // ЧПУ END

    /*Отображение каталога*/
    public function fetch() {
        if ($this->is_wrong_params) {
            return false;
        }
        // GET-Параметры
        $category_url = $this->request->get('category', 'string');
        $brand_url    = $this->request->get('brand', 'string');
        
        $filter = array();
        $filter['visible'] = 1;
        
        // Если задан бренд, выберем его из базы
        $prices = array();
        $prices['current'] = $this->request->get('p');
        if (isset($prices['current']['min']) && isset($prices['current']['max']) && $prices['current']['max'] != '' && $prices['current']['min'] != '') {
            $filter['price'] = $prices['current'];
        } else {
            unset($prices['current']);
        }

        if ($val = $this->request->get('b')) {
            $filter['brand_id'] = $val;
        } elseif (!empty($brand_url)) {
            $brand = $this->brands->get_brand((string)$brand_url);
            if (empty($brand)) {
                return false;
            }
            $this->design->assign('brand', $brand);
            $filter['brand_id'] = $brand->id;
        }
        
        // Выберем текущую категорию
        if (!empty($category_url)) {
            $category = $this->categories->get_category((string)$category_url);
            if (empty($category) || (!$category->visible && empty($_SESSION['admin']))) {
                return false;
            }
            $this->design->assign('category', $category);
            $filter['category_id'] = $category->children;
        }
        
        // Если задано ключевое слово
        $keyword = $this->request->get('keyword');
        if (!empty($keyword)) {
            $this->design->assign('keyword', $keyword);
            $filter['keyword'] = $keyword;
        }

        $mode = $this->request->get('mode');
        if (!empty($mode)) {
            if ($mode == 'bestsellers') {
                $filter['featured'] = 1;
            } elseif ($mode == 'discounted') {
                $filter['discounted'] = 1;
            }
        }
        
        // Сортировка товаров, сохраняем в сесси, чтобы текущая сортировка оставалась для всего сайта
        if($sort = $this->request->get('sort', 'string')) {
            $_SESSION['sort'] = $sort;
        }
        if (!empty($_SESSION['sort'])) {
            $filter['sort'] = $_SESSION['sort'];
        } else {
            $filter['sort'] = 'position';
        }
        $this->design->assign('sort', $filter['sort']);
        
        // Свойства товаров
        if(!empty($category)) {
            $features = array();
            foreach($this->features->get_features(array('category_id'=>$category->id, 'in_filter'=>1)) as $feature) {
                $features[$feature->id] = $feature;
                $this->features_urls[] = $feature->url;
                if($val = $this->request->get($feature->id)) {
                    $filter['features'][$feature->id] = $val;
                }
            }
            
            $options_filter['visible'] = 1;
            
            $features_ids = array_keys($features);
            if(!empty($features_ids)) {
                $options_filter['feature_id'] = $features_ids;
            }
            $options_filter['category_id'] = $category->children;
            if(isset($filter['features'])) {
                $options_filter['features'] = $filter['features'];
            }
            if(!empty($brand)) {
                $options_filter['brand_id'] = $brand->id;
            } elseif(isset($filter['brand_id'])) {
                $options_filter['brand_id'] = $filter['brand_id'];
            }
            
            $options = $this->features->get_options($options_filter);
            
            foreach($options as $option) {
                if(isset($features[$option->feature_id])) {
                    $features[$option->feature_id]->options[] = $option;
                }
            }
            
            foreach($features as $i=>$feature) {
                if(empty($feature->options)) {
                    unset($features[$i]);
                }
            }
            $this->design->assign('features', $features);
        }
        
        // Постраничная навигация
        $items_per_page = $this->settings->products_num;
        // Текущая страница в постраничном выводе
        $current_page = $this->request->get('page', 'integer');
        // Если не задана, то равна 1
        $current_page = max(1, $current_page);
        $this->design->assign('current_page_num', $current_page);
        // Вычисляем количество страниц
        $products_count = $this->products->count_products($filter);
        
        // Показать все страницы сразу
        if($this->request->get('page') == 'all') {
            $items_per_page = $products_count;
        }
        
        $pages_num = ceil($products_count/$items_per_page);
        $this->design->assign('total_pages_num', $pages_num);
        $this->design->assign('total_products_num', $products_count);
        
        $filter['page'] = $current_page;
        $filter['limit'] = $items_per_page;

        if ($this->request->get('page') != 'all' && $current_page > 1 && $current_page > $pages_num) {
            return false;
        }
        //lastModify
        $last_modify = array();
        $brand_id_filter = '';
        $category_id_filter = '';
        if(!empty($filter['brand_id'])) {
            $brand_id_filter = $this->db->placehold('AND p.brand_id in(?@)', (array)$filter['brand_id']);
            if(!empty($brand)){
                $last_modify[] = $brand->last_modify;
            }
        }
        if(!empty($filter['category_id'])) {
            $category_id_filter = $this->db->placehold('INNER JOIN __products_categories pc ON pc.product_id = p.id AND pc.category_id in(?@)', (array)$filter['category_id']);
            $last_modify[] = $category->last_modify;
        }
        $this->db->query("SELECT MAX(p.last_modify) as last_modify
            FROM __products p
            $category_id_filter
            WHERE 1 $brand_id_filter");
        $res = $this->db->result('last_modify');
        if (!empty($res)) {
            $last_modify[] = $res;
        }
        if ($this->page) {
            $last_modify[] = $this->page->last_modify;
        }
        $this->setHeaderLastModify(max($last_modify));
        //lastModify END
        /*Постраничная навигация END*/

        // Товары
        $products = array();
        foreach($this->products->get_products($filter) as $p) {
            $products[$p->id] = $p;
        }
        
        // Если искали товар и найден ровно один - перенаправляем на него
        if(!empty($keyword) && $products_count == 1 && !$this->request->get('ajax','boolean')) {
            header('Location: '.$this->config->root_url.'/'.$this->lang_link.'products/'.$p->url);
        }
        
        if(!empty($products)) {
            $products_ids = array_keys($products);
            foreach($products as $product) {
                $product->variants = array();
                $product->images = array();
                $product->properties = array();
            }

            $variants = $this->variants->get_variants(array('product_id'=>$products_ids));

            foreach($variants as $variant) {
                $products[$variant->product_id]->variants[] = $variant;
            }

            $images = $this->products->get_images(array('product_id'=>$products_ids));
            foreach($images as $image) {
                $products[$image->product_id]->images[] = $image;
            }

            foreach($products as $product) {
                if(isset($product->variants[0])) {
                    $product->variant = $product->variants[0];
                }
                if(isset($product->images[0])) {
                    $product->image = $product->images[0];
                }
            }
            $this->design->assign('products', $products);
        }
        
        // Выбираем бренды, они нужны нам в шаблоне
        if(!empty($category)) {
            $this->category_brands = $this->brands->get_brands(array('category_id'=>$category->children, 'visible'=>1, 'features'=>$filter['features']));
            $category->brands = $this->category_brands;
        }
        
        if(isset($prices['current'])) {
            $prices['current'] = (object)$prices['current'];
        }
        $prices = (object)$prices;
        $range_filter = $filter;
        $range_filter['get_price'] = 1;
        $prices->range = $this->products->count_products($range_filter);
        $this->design->assign('prices', $prices);
        if($this->request->get('ajax','boolean')) {
            $this->design->assign('ajax', 1);
            $result = new StdClass;
            $result->products_content = $this->design->fetch('products_content.tpl');
            $result->products_pagination = $this->design->fetch('chpu_pagination.tpl');
            $result->products_sort = $this->design->fetch('products_sort.tpl');
            print json_encode($result);
            die;
        }
        
        // Устанавливаем мета-теги в зависимости от запроса
        if($this->page) {
            $this->design->assign('meta_title', $this->page->meta_title);
            $this->design->assign('meta_keywords', $this->page->meta_keywords);
            $this->design->assign('meta_description', $this->page->meta_description);
        } elseif(isset($category)) {
            $this->design->assign('meta_title', $category->meta_title);
            $this->design->assign('meta_keywords', $category->meta_keywords);
            $this->design->assign('meta_description', $category->meta_description);
        } elseif(isset($brand)) {
            $this->design->assign('meta_title', $brand->meta_title);
            $this->design->assign('meta_keywords', $brand->meta_keywords);
            $this->design->assign('meta_description', $brand->meta_description);
        } elseif(isset($keyword)) {
            $this->design->assign('meta_title', $keyword);
        }

        $rel_prev_next = $this->design->fetch('products_rel_prev_next.tpl');
        $this->design->assign('rel_prev_next', $rel_prev_next);
        $this->design->assign('sort_canonical', $this->filter_chpu_url(array('sort'=>null), $this->design));

        $this->body = $this->design->fetch('products.tpl');
        return $this->body;
    }
    
}