ProductFrontendSearch.php 6.51 KB
<?php
    
    namespace frontend\models;
    
    use common\modules\product\helpers\ProductHelper;
    use common\modules\product\models\Category;
    use yii\base\Model;
    use yii\data\ArrayDataProvider;
    use yii\db\ActiveQuery;
    
    use common\modules\product\models\Product;
    use common\modules\product\models\ProductVariant;
    use yii\db\Query;
    
    class ProductFrontendSearch extends Product
    {
        
        public $price_interval;
        public $brands;
        
        /**
         * @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 ArrayDataProvider
         */
        public function search($category = null, $params = [], $in_stock = true, $without_sale = true)
        {
            
            $dataProvider = new ArrayDataProvider(
                [
                    'allModels'  => $this->getSearchQuery($category, $params, $in_stock, $without_sale)
                                         ->with(
                                             [
                                                 'images',
                                                 'events',
                                                 'variant',
                                                 'variant.image',
                                                 'comments',
                                                 'averageRating',
                                             ]
                                         )
                                         ->all(),
                    'pagination' => [
                        'pageSize' => 15,
                    ],
                    'sort'       => [
                        'attributes' => [
                            'name'  => [
                                'asc'     => [ 'name' => SORT_ASC ],
                                'desc'    => [ 'name' => SORT_DESC ],
                                'default' => SORT_DESC,
                                'label'   => 'имени',
                            ],
                            'price' => [
                                'asc'     => [ 'price' => SORT_ASC ],
                                'desc'    => [ 'price' => SORT_DESC ],
                                'default' => SORT_DESC,
                                'label'   => 'по цене',
                            ],
                        ],
                    ],
                ]
            );
            
            return $dataProvider;
        }
        
        public function getSearchQuery($category = null, $params = [], $in_stock = true, $without_sale = true)
        {
            
            if (!empty($category)) {
                /** @var ActiveQuery $query */
                /**@var Category $category * */
                $query = $category->getProducts();
                
            } else {
                $query = Product::find();
            }
            
            $query->select([ 'product.*' ]);
            $query->joinWith(
                [
                    'enabledVariants',
                    'brand',
                    'options',
                    'category',
                ]
            );
            
            //        $query->groupBy(['product.product_id', 'product_variant.price', 'product_variant.stock']);
            $query->orderBy([
                'brand.sort' => SORT_ASC,
                'product_variant.stock' => SORT_DESC,
                            ]);
            ProductHelper::_setQueryParams($query, $params);
            if ($in_stock) {
                $query->andWhere(
                    [
                        '!=',
                        ProductVariant::tableName() . '.status',
                        1,
                    ]
                );
            }
            
            /**
             * Removing products that currently in events
             */
            if ($without_sale) {
                $query->andWhere(
                    [
                        'not',
                        [
                            'product.product_id' => ( new Query() )->select('events_to_products.product_id')
                                                                   ->from('events_to_products')
                                                                   ->innerJoin(
                                                                       'event',
                                                                       'event.event_id=events_to_products.event_id'
                                                                   )->where(['event.sale' => true]),
                        ],
                    ]
                );
            }
            
            return $query;
        }
        
        /**
         * @param Category|null $category
         *
         * @return array
         */
        
        public function priceLimits($category = null, $params = [])
        {
            if (!empty($category)) {
                /** @var ActiveQuery $query */
                //            $query = $category->getRelations('product_categories');
                $query = $category->getProducts();
            } else {
                $query = Product::find();
            }
            $query->joinWith('variant');
            
            // Price filter fix
            unset($params[ 'prices' ]);
            
            ProductHelper::_setQueryParams($query, $params);
            $query->andWhere(
                [
                    '>=',
                    ProductVariant::tableName() . '.stock',
                    1,
                ]
            );
            return [
                'min' => $query->min(ProductVariant::tableName() . '.price'),
                'max' => $query->max(ProductVariant::tableName() . '.price'),
            ];
        }
    }