ProductFrontendSearch.php 6.77 KB
<?php

namespace frontend\models;

use common\modules\product\models\Brand;
use common\modules\product\models\ProductCategory;
use common\modules\product\models\ProductOption;
use common\modules\product\models\ProductSearch;
use common\modules\rubrication\models\TaxGroup;
use common\modules\rubrication\models\TaxOption;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\web\NotFoundHttpException;
use common\modules\product\models\Product;
use common\modules\product\models\ProductVariant;

class ProductFrontendSearch extends Product {
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['price_interval', 'brands'], 'safe'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function scenarios()
    {
        // bypass scenarios() implementation in the parent class
        return Model::scenarios();
    }

    /**
     * Creates data provider instance with search query applied for frontend
     *
     * @param array $params
     *
     * @return ActiveDataProvider
     */
    public function search($category = null, $params = []) {
        if (!empty($category)) {
            /** @var ActiveQuery $query */
            $query = $category->getRelations('product_categories');
        } else {
            $query = Product::find();
        }
        $query->joinWith('variant');
        $query->joinWith('brand');
        $query->joinWith('image');
        $query->joinWith('categories');

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 24,
            ],
            'sort' => [
                'attributes' => [
                    'name' => [
                        'asc' => ['name' => SORT_ASC],
                        'desc' => ['name' => SORT_DESC],
                        'default' => SORT_DESC,
                        'label' => 'имени',
                    ],
                    'price' => [
                        'asc' => [ProductVariant::tableName() .'.price' => SORT_ASC],
                        'desc' => [ProductVariant::tableName() .'.price' => SORT_DESC],
                        'default' => SORT_DESC,
                        'label' => 'цене',
                    ],
                ],
            ]
        ]);

        if (!$this->validate()) {
            return $dataProvider;
        }

        $this->_setParams($query, $params);

        return $dataProvider;
    }

    public function optionsForCategory($category = null, $params = []) {
        $query = TaxOption::find()
            ->select([
                TaxOption::tableName() .'.*',
                'COUNT('. ProductOption::tableName() .'.product_id) AS _items_count'
            ])
            ->innerJoin(ProductOption::tableName(), ProductOption::tableName() .'.option_id='. TaxOption::tableName() .'.tax_option_id')
            ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. ProductOption::tableName() .'.product_id')
            ->innerJoin(TaxGroup::tableName(), TaxGroup::tableName() .'.tax_group_id='. TaxOption::tableName() .'.tax_group_id')
            ->andWhere([TaxGroup::tableName() .'.is_filter' => true]);
        if (!empty($category)) {
            $query->andWhere([ProductCategory::tableName() .'.category_id' => $category->category_id]);
        }
        $query->groupBy(TaxOption::tableName() .'.tax_option_id');

        if (!empty($params['prices'])) {
            if ($params['prices']['min'] > 0 || $params['prices']['max'] > 0) {
                $query->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id='. ProductCategory::tableName() .'.product_id');
            }
            if ($params['prices']['min'] > 0) {
                $query->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
            }
            if ($params['prices']['max'] > 0) {
                $query->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
            }
        }
        if (!empty($params['brands'])) {
            $query->innerJoin(Product::tableName(), Product::tableName() .'.product_id='. ProductCategory::tableName() .'.product_id');
            $query->andWhere([Product::tableName() .'.brand_id' => $params['brands']]);
        }

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);

        return $dataProvider;
    }

    public function priceLimits($category = null, $params = []) {
        if (!empty($category)) {
            /** @var ActiveQuery $query */
            $query = $category->getRelations('product_categories');
        } else {
            $query = Product::find();
        }
        $query->joinWith('variant');

        $this->_setParams($query, $params, false);

//        $query->select([
//            'MIN('. ProductVariant::tableName() .'.price) AS priceMIN',
//            'MAX('. ProductVariant::tableName() .'.price) AS priceMAX',
//        ]);

        return [
            'min' => $query->min(ProductVariant::tableName() .'.price'),
            'max' => $query->max(ProductVariant::tableName() .'.price'),
        ];
    }

    protected function _setParams(&$query, $params, $setPriceLimits = true) {
        if (!empty($params['keywords'])) {
            if (!is_array($params['keywords'])) {
                $params['keywords'] = [$params['keywords']];
            }
            foreach ($params['keywords'] as $keyword) {
                $query->andFilterWhere(['ilike', Product::tableName() .'.name', $keyword]);
            }
        }
        if (!empty($params['brands'])) {
            $query->andFilterWhere([Product::tableName() .'.brand_id' => $params['brands']]);
        }
        if (!empty($params['options'])) {
            foreach ($params['options'] as $group => $options) {
                foreach ($options as &$option) {
                    $option = "'$option'";
                }
                $query->andWhere(
                    Product::tableName() . '.product_id IN (SELECT product_id AS products FROM product_option INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id WHERE tax_group.alias LIKE \''. $group .'\' AND tax_option.alias IN (' . implode(',', $options) . '))'
                );
            }
        }
        if ($setPriceLimits && !empty($params['prices'])) {
            if ($params['prices']['min'] > 0) {
                $query->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
            }
            if ($params['prices']['max'] > 0) {
                $query->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
            }
        }
    }
}