Commit b519af228167867d15d4e91e1113387838daed3f

Authored by Karnovsky A
1 parent 9d33ce37

Base-product functional

common/components/artboxtree/ArtboxTreeBehavior.php
@@ -20,6 +20,7 @@ class ArtboxTreeBehavior extends Behavior { @@ -20,6 +20,7 @@ class ArtboxTreeBehavior extends Behavior {
20 public $keyNameGroup = 'group'; 20 public $keyNameGroup = 'group';
21 public $keyNamePath = 'path_int'; 21 public $keyNamePath = 'path_int';
22 public $keyNameDepth = 'depth'; // @todo -> $keyNameDepth; 22 public $keyNameDepth = 'depth'; // @todo -> $keyNameDepth;
  23 + public $primaryKeyMode = true;
23 24
24 /** 25 /**
25 * @var string 26 * @var string
@@ -88,8 +89,31 @@ class ArtboxTreeBehavior extends Behavior { @@ -88,8 +89,31 @@ class ArtboxTreeBehavior extends Behavior {
88 * get all-level children items 89 * get all-level children items
89 * use MP-method 90 * use MP-method
90 */ 91 */
91 - public function getAllChildren($depth = null) {  
92 - return $this->getAllChildrenMP($depth); 92 + public function getAllChildren($depth = null, $where = []) {
  93 + return $this->getAllChildrenMP($depth)->where($where);
  94 + }
  95 +
  96 + /*
  97 + * get all-level children items
  98 + * use MP-method
  99 + */
  100 + public function getAllChildrenTree($depth = null, $where = []) {
  101 + return $this->buildTree($this->getAllChildrenMP($depth, $where)->all(), $this->owner->getAttribute($this->keyNameId));
  102 + }
  103 +
  104 + protected function buildTree(array $data, $parentId = 0) {
  105 + $result = [];
  106 + foreach ($data as $key => $element) {
  107 + if ($element->getAttribute($this->keyNameParentId) == $parentId) {
  108 + unset($data[$key]);
  109 + $children = $this->buildTree($data, $element->getAttribute($this->keyNameId));
  110 + $result[] = [
  111 + 'item' => $element,
  112 + 'children' => $children
  113 + ];
  114 + }
  115 + }
  116 + return $result;
93 } 117 }
94 118
95 119
@@ -103,9 +127,30 @@ class ArtboxTreeBehavior extends Behavior { @@ -103,9 +127,30 @@ class ArtboxTreeBehavior extends Behavior {
103 * Full-path (use MP-method) 127 * Full-path (use MP-method)
104 */ 128 */
105 public function getParentsMP($depth = null) { 129 public function getParentsMP($depth = null) {
  130 + $tableName = $this->owner->tableName();
  131 + $path = $this->owner->getAttribute($this->keyNamePath);
  132 + $query = $this->owner->find()
  133 + ->andWhere(['<@', "{$tableName}.[[{$this->keyNamePath}]]", $path]);
  134 + if ($depth > 0) {
  135 + $query->andWhere(['>=', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth) - $depth]);
  136 + }
  137 + $query->andWhere(['<', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth)]);
  138 +
  139 + $orderBy = [];
  140 + $orderBy["{$tableName}.[[{$this->keyNameDepth}]]"] = SORT_ASC;
  141 + $orderBy["{$tableName}.[[{$this->keyNameId}]]"] = SORT_ASC;
  142 +
  143 + $query
  144 + ->andWhere($this->groupWhere())
  145 + ->addOrderBy($orderBy);
  146 + $query->multiple = true;
  147 +
  148 + return $query;
  149 + }
  150 + /*public function getParentsMP($depth = null) {
106 $path = $this->getParentPath(); 151 $path = $this->getParentPath();
107 if ($path !== null) { 152 if ($path !== null) {
108 - $paths = str_replace(['{', '}'], '', explode(',', $path)); 153 + $paths = explode(',', trim($path, '{}'));
109 if (!$this->primaryKeyMode) { 154 if (!$this->primaryKeyMode) {
110 $path = null; 155 $path = null;
111 $paths = array_map( 156 $paths = array_map(
@@ -123,7 +168,6 @@ class ArtboxTreeBehavior extends Behavior { @@ -123,7 +168,6 @@ class ArtboxTreeBehavior extends Behavior {
123 } 168 }
124 169
125 $tableName = $this->owner->tableName(); 170 $tableName = $this->owner->tableName();
126 - $condition = ['and'];  
127 if ($this->primaryKeyMode) { 171 if ($this->primaryKeyMode) {
128 $condition[] = ["{$tableName}.[[{$this->keyNameId}]]" => $paths]; 172 $condition[] = ["{$tableName}.[[{$this->keyNameId}]]" => $paths];
129 } else { 173 } else {
@@ -132,12 +176,12 @@ class ArtboxTreeBehavior extends Behavior { @@ -132,12 +176,12 @@ class ArtboxTreeBehavior extends Behavior {
132 176
133 $query = $this->owner->find() 177 $query = $this->owner->find()
134 ->andWhere($condition) 178 ->andWhere($condition)
135 - ->andWhere($this->treeCondition()) 179 + ->andWhere($this->groupWhere())
136 ->addOrderBy(["{$tableName}.[[{$this->keyNamePath}]]" => SORT_ASC]); 180 ->addOrderBy(["{$tableName}.[[{$this->keyNamePath}]]" => SORT_ASC]);
137 $query->multiple = true; 181 $query->multiple = true;
138 182
139 return $query; 183 return $query;
140 - } 184 + }*/
141 185
142 /** 186 /**
143 * @param bool $asArray = false 187 * @param bool $asArray = false
@@ -147,14 +191,26 @@ class ArtboxTreeBehavior extends Behavior { @@ -147,14 +191,26 @@ class ArtboxTreeBehavior extends Behavior {
147 { 191 {
148 return static::getParentPathInternal($this->owner->getAttribute($this->keyNamePath), $asArray); 192 return static::getParentPathInternal($this->owner->getAttribute($this->keyNamePath), $asArray);
149 } 193 }
  194 + /**
  195 + * @return array
  196 + */
  197 + protected function groupWhere()
  198 + {
  199 + $tableName = $this->owner->tableName();
  200 + if ($this->keyNameGroup === null) {
  201 + return [];
  202 + } else {
  203 + return ["{$tableName}.[[{$this->keyNameGroup}]]" => $this->owner->getAttribute($this->keyNameGroup)];
  204 + }
  205 + }
  206 +
150 207
151 public function getAllChildrenMP($depth = null) 208 public function getAllChildrenMP($depth = null)
152 { 209 {
153 $tableName = $this->owner->tableName(); 210 $tableName = $this->owner->tableName();
154 $path = $this->owner->getAttribute($this->keyNamePath); 211 $path = $this->owner->getAttribute($this->keyNamePath);
155 $query = $this->owner->find() 212 $query = $this->owner->find()
156 - ->andWhere(['@>', "{$tableName}.[[{$this->keyNamePath}]]", $this->getLike($path), false]);  
157 - 213 + ->andWhere(['@>', "{$tableName}.[[{$this->keyNamePath}]]", $path]);
158 214
159 if ($depth > 0) { 215 if ($depth > 0) {
160 $query->andWhere(['<=', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth) + $depth]); 216 $query->andWhere(['<=', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth) + $depth]);
@@ -165,7 +221,7 @@ class ArtboxTreeBehavior extends Behavior { @@ -165,7 +221,7 @@ class ArtboxTreeBehavior extends Behavior {
165 $orderBy["{$tableName}.[[{$this->keyNameId}]]"] = SORT_ASC; 221 $orderBy["{$tableName}.[[{$this->keyNameId}]]"] = SORT_ASC;
166 222
167 $query 223 $query
168 - ->andWhere($this->treeCondition()) 224 + ->andWhere($this->groupWhere())
169 ->addOrderBy($orderBy); 225 ->addOrderBy($orderBy);
170 $query->multiple = true; 226 $query->multiple = true;
171 227
@@ -186,7 +242,13 @@ class ArtboxTreeBehavior extends Behavior { @@ -186,7 +242,13 @@ class ArtboxTreeBehavior extends Behavior {
186 $parent_id = $this->owner->getAttribute($this->keyNameParentId); 242 $parent_id = $this->owner->getAttribute($this->keyNameParentId);
187 if (empty($parent_id)) 243 if (empty($parent_id))
188 return null; 244 return null;
189 - return $this->owner->find()->where([$this->keyNameId => $parent_id, $this->keyNameGroup => $this->owner->getAttribute($this->keyNameGroup)])->one(); 245 +
  246 + $where = [$this->keyNameId => $parent_id];
  247 + if ($this->keyNameGroup) {
  248 + $where[$this->keyNameGroup] = $this->owner->getAttribute($this->keyNameGroup);
  249 + }
  250 +
  251 + return $this->owner->find()->where($where)->one();
190 } 252 }
191 253
192 /* 254 /*
@@ -216,7 +278,11 @@ class ArtboxTreeBehavior extends Behavior { @@ -216,7 +278,11 @@ class ArtboxTreeBehavior extends Behavior {
216 * @return ActiveQuery 278 * @return ActiveQuery
217 */ 279 */
218 public function getChildrenAL() { 280 public function getChildrenAL() {
219 - return $this->owner->find()->where([$this->keyNameParentId => $this->owner->getAttribute($this->keyNameId), $this->keyNameGroup => $this->owner->getAttribute($this->keyNameGroup)]); 281 + $where = [$this->keyNameParentId => $this->owner->getAttribute($this->keyNameId)];
  282 + if ($this->keyNameGroup) {
  283 + $where[$this->keyNameGroup] = $this->owner->getAttribute($this->keyNameGroup);
  284 + }
  285 + return $this->owner->find()->where($where);
220 } 286 }
221 287
222 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 288 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -271,7 +337,7 @@ class ArtboxTreeBehavior extends Behavior { @@ -271,7 +337,7 @@ class ArtboxTreeBehavior extends Behavior {
271 */ 337 */
272 protected static function getParentPathInternal($path, $asArray = false) 338 protected static function getParentPathInternal($path, $asArray = false)
273 { 339 {
274 - $path = str_replace(['{', '}'], '', explode(',', $path)); 340 + $path = explode(',', trim($path, '{}'));
275 array_pop($path); 341 array_pop($path);
276 if ($asArray) { 342 if ($asArray) {
277 return $path; 343 return $path;
@@ -348,7 +414,7 @@ class ArtboxTreeBehavior extends Behavior { @@ -348,7 +414,7 @@ class ArtboxTreeBehavior extends Behavior {
348 // $this->keyNamePath => $path 414 // $this->keyNamePath => $path
349 // ]); 415 // ]);
350 416
351 - $this->owner->setAttribute('path_int', $path); 417 + $this->owner->setAttribute($this->keyNamePath, $path);
352 // $this->owner->setAttribute($this->keyNamePath, $path); 418 // $this->owner->setAttribute($this->keyNamePath, $path);
353 $this->owner->setAttribute($this->keyNameDepth, $depth); 419 $this->owner->setAttribute($this->keyNameDepth, $depth);
354 } 420 }
common/components/artboxtree/ArtboxTreeQueryTrait.php
@@ -23,18 +23,17 @@ trait ArtboxTreeQueryTrait { @@ -23,18 +23,17 @@ trait ArtboxTreeQueryTrait {
23 return self::$model; 23 return self::$model;
24 } 24 }
25 25
26 - public function getTree($group, $cached = true) {  
27 - if ($cached && isset(self::$cache_tree[$group]))  
28 - return self::$cache_tree[$group];  
29 - 26 + public function getTree($group = null) {
30 $model = $this->getModel(); 27 $model = $this->getModel();
31 - $data = $this->andWhere([$model->keyNameGroup => $group])->all(); 28 + if ($group !== null) {
  29 + $data = $this->andWhere([$model->keyNameGroup => $group])->all();
  30 + } else {
  31 + $data = $this->all();
  32 + }
32 if (empty($data)) 33 if (empty($data))
33 return []; 34 return [];
34 35
35 - self::$cache_tree[$group] = $this->buildTree($data);  
36 -  
37 - return self::$cache_tree[$group]; 36 + return $this->buildTree($data);
38 } 37 }
39 38
40 private function _recursiveRebuild($tree, $parentPath = null, $depth = 0) { 39 private function _recursiveRebuild($tree, $parentPath = null, $depth = 0) {
common/config/main.php
@@ -86,16 +86,13 @@ return [ @@ -86,16 +86,13 @@ return [
86 'linked_key' => 'product_id', 86 'linked_key' => 'product_id',
87 ], 87 ],
88 'entity2' => [ 88 'entity2' => [
89 - 'model' => '\common\modules\rubrication\models\TaxOption', 89 + 'model' => '\common\modules\product\models\Category',
90 'label' => 'Category', 90 'label' => 'Category',
91 - 'listField' => 'ValueRenderFlash',  
92 - 'key' => 'tax_option_id', 91 + 'listField' => 'name',
  92 + 'key' => 'category_id',
93 'linked_key' => 'category_id', 93 'linked_key' => 'category_id',
94 - 'where' => [  
95 - 'tax_group_id' => 1  
96 - ],  
97 'hierarchy' => [ 94 'hierarchy' => [
98 - 'key' => 'tax_option_id', 95 + 'key' => 'category_id',
99 'parentKey' => 'parent_id', 96 'parentKey' => 'parent_id',
100 ] 97 ]
101 ], 98 ],
@@ -103,6 +100,33 @@ return [ @@ -103,6 +100,33 @@ return [
103 'model' => '\common\modules\product\models\ProductCategory', 100 'model' => '\common\modules\product\models\ProductCategory',
104 ] 101 ]
105 ], 102 ],
  103 + 'tax_group_to_category' => [
  104 + 'name' => Yii::t('product', 'Характеристики по категориям'),
  105 + 'field' => 'option_to_category',
  106 + 'entity1' => [
  107 + 'model' => '\common\modules\rubrication\models\TaxGroup',
  108 + 'label' => 'Group',
  109 + 'listField' => 'name',
  110 + 'key' => 'tax_group_id',
  111 + 'linked_key' => 'entity1_id',
  112 + ],
  113 + 'entity2' => [
  114 + 'model' => '\common\modules\product\models\Category',
  115 + 'label' => 'Category',
  116 + 'listField' => 'name',
  117 + 'key' => 'category_id',
  118 + 'linked_key' => 'entity2_id',
  119 + 'hierarchy' => [
  120 + 'key' => 'category_id',
  121 + 'parentKey' => 'parent_id',
  122 + ]
  123 + ],
  124 + 'via' => [
  125 + 'model' => '\common\modules\relation\models\Relation',
  126 + 'alias' => 'alias',
  127 + ]
  128 + ],
  129 + /*
106 'relation_categories' => [ 130 'relation_categories' => [
107 'name' => Yii::t('relation', 'Relation categories'), 131 'name' => Yii::t('relation', 'Relation categories'),
108 'field' => 'categories', 132 'field' => 'categories',
@@ -194,7 +218,7 @@ return [ @@ -194,7 +218,7 @@ return [
194 'model' => 'common\modules\rubrication\models\TaxOptionRelation', 218 'model' => 'common\modules\rubrication\models\TaxOptionRelation',
195 'alias' => 'alias', 219 'alias' => 'alias',
196 ] 220 ]
197 - ] 221 + ]*/
198 ] 222 ]
199 ], 223 ],
200 'comment' => [ 224 'comment' => [
common/modules/product/controllers/ManageController.php
@@ -2,6 +2,9 @@ @@ -2,6 +2,9 @@
2 2
3 namespace common\modules\product\controllers; 3 namespace common\modules\product\controllers;
4 4
  5 +use common\modules\product\helpers\ProductHelper;
  6 +use common\modules\product\models\Category;
  7 +use common\modules\product\models\ProductVariant;
5 use Yii; 8 use Yii;
6 use common\modules\product\models\Product; 9 use common\modules\product\models\Product;
7 use common\modules\product\models\ProductSearch; 10 use common\modules\product\models\ProductSearch;
@@ -29,6 +32,38 @@ class ManageController extends Controller @@ -29,6 +32,38 @@ class ManageController extends Controller
29 ]; 32 ];
30 } 33 }
31 34
  35 + public function actionTest() {
  36 + $categories = Category::find()->where(['depth' => 2])->all();
  37 + $cats_ids = [];
  38 + foreach($categories as $cat) {
  39 + $cats_ids[] = $cat->category_id;
  40 + }
  41 +
  42 + $brands = ProductHelper::getBrands()->all();
  43 + $brands_ids = [];
  44 + foreach($brands as $brand) {
  45 + $brands_ids[] = $brand->brand_id;
  46 + }
  47 +
  48 + for($i=1;$i<=1000;$i++) {
  49 + $uniqid = uniqid();
  50 + $model = new Product();
  51 + $model->name = 'Test '. $uniqid;
  52 + $model->brand_id = $brands_ids[array_rand($brands_ids, 1)];
  53 + $model->categories = [$cats_ids[array_rand($cats_ids, 1)]];
  54 + $model->save();
  55 +
  56 + $variantModel = new ProductVariant();
  57 + $variantModel->product_id = $model->product_id;
  58 + $variantModel->name = 'test-'. $uniqid;
  59 + $variantModel->sku = $variantModel->name;
  60 + $variantModel->price = rand(5, 200000);
  61 + $variantModel->price_old = rand(0, 5) > 3 ? $variantModel->price* (1+rand(0, 10) / 10) : $variantModel->price;
  62 + $variantModel->product_unit_id = rand(1, 5);
  63 + $variantModel->save();
  64 + }
  65 + }
  66 +
32 /** 67 /**
33 * Lists all Product models. 68 * Lists all Product models.
34 * @return mixed 69 * @return mixed
common/modules/product/helpers/ProductHelper.php
@@ -2,23 +2,16 @@ @@ -2,23 +2,16 @@
2 2
3 namespace common\modules\product\helpers; 3 namespace common\modules\product\helpers;
4 4
5 -use common\modules\rubrication\models\TaxOption; 5 +use common\modules\product\models\Brand;
  6 +use common\modules\product\models\Category;
6 use yii\base\Object; 7 use yii\base\Object;
7 8
8 class ProductHelper extends Object { 9 class ProductHelper extends Object {
9 - public static function getCategoryGroupId() {  
10 - return \Yii::$app->getModule('product')->params['category_group'];  
11 - }  
12 -  
13 - public static function getBrandGroupId() {  
14 - return \Yii::$app->getModule('product')->params['brand_group'];  
15 - }  
16 -  
17 public static function getCategories() { 10 public static function getCategories() {
18 - return TaxOption::find()->getTree(self::getCategoryGroupId()); 11 + return Category::find()->getTree();
19 } 12 }
20 13
21 public static function getBrands() { 14 public static function getBrands() {
22 - return TaxOption::find()->where(['tax_group_id' => self::getBrandGroupId()]); 15 + return Brand::find();
23 } 16 }
24 } 17 }
25 \ No newline at end of file 18 \ No newline at end of file
common/modules/product/models/Category.php
@@ -4,6 +4,7 @@ namespace common\modules\product\models; @@ -4,6 +4,7 @@ namespace common\modules\product\models;
4 4
5 use common\behaviors\Slug; 5 use common\behaviors\Slug;
6 use common\components\artboxtree\ArtboxTreeBehavior; 6 use common\components\artboxtree\ArtboxTreeBehavior;
  7 +use common\modules\relation\relationBehavior;
7 use common\modules\rubrication\behaviors\ArtboxSynonymBehavior; 8 use common\modules\rubrication\behaviors\ArtboxSynonymBehavior;
8 use Yii; 9 use Yii;
9 10
@@ -53,6 +54,12 @@ class Category extends \yii\db\ActiveRecord @@ -53,6 +54,12 @@ class Category extends \yii\db\ActiveRecord
53 'valueFields' => [ // postKey => DBFieldName 54 'valueFields' => [ // postKey => DBFieldName
54 'name' => 'value' 55 'name' => 'value'
55 ] 56 ]
  57 + ],
  58 + [
  59 + 'class' => relationBehavior::className(),
  60 + 'relations' => [
  61 + 'product_categories' => 'entity2' // Products of category
  62 + ]
56 ] 63 ]
57 ]; 64 ];
58 } 65 }
common/modules/product/models/Product.php
@@ -11,13 +11,18 @@ use yii\db\ActiveQuery; @@ -11,13 +11,18 @@ use yii\db\ActiveQuery;
11 * This is the model class for table "{{%product}}". 11 * This is the model class for table "{{%product}}".
12 * 12 *
13 * @property string $name 13 * @property string $name
14 - * @property integer $tax_brand_id 14 + * @property integer $brand_id
15 * @property integer $product_id 15 * @property integer $product_id
16 - *  
17 - * @property TaxOption $categories 16 + * @property Category $category
  17 + * @property array $categories
  18 + * @property ProductVariant $variant
  19 + * @property ProductImage $image
  20 + * @property array $images
18 */ 21 */
19 class Product extends \yii\db\ActiveRecord 22 class Product extends \yii\db\ActiveRecord
20 { 23 {
  24 + /** @var array $variants */
  25 + public $_variants = [];
21 /** 26 /**
22 * @inheritdoc 27 * @inheritdoc
23 */ 28 */
@@ -47,9 +52,9 @@ class Product extends \yii\db\ActiveRecord @@ -47,9 +52,9 @@ class Product extends \yii\db\ActiveRecord
47 public function rules() 52 public function rules()
48 { 53 {
49 return [ 54 return [
50 - [['tax_brand_id'], 'integer'], 55 + [['brand_id'], 'integer'],
51 [['name'], 'string', 'max' => 150], 56 [['name'], 'string', 'max' => 150],
52 - [['categories'], 'safe'], 57 + [['categories', 'variants'], 'safe'],
53 // [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']], 58 // [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
54 ]; 59 ];
55 } 60 }
@@ -60,11 +65,11 @@ class Product extends \yii\db\ActiveRecord @@ -60,11 +65,11 @@ class Product extends \yii\db\ActiveRecord
60 public function attributeLabels() 65 public function attributeLabels()
61 { 66 {
62 return [ 67 return [
63 - 'product_id' => Yii::t('product', 'Product ID'), 68 + 'product_id' => Yii::t('product', 'ID'),
64 'name' => Yii::t('product', 'Name'), 69 'name' => Yii::t('product', 'Name'),
65 - 'tax_brand_id' => Yii::t('product', 'Brand'),  
66 - 'brand' => Yii::t('product', 'Brand'), 70 + 'brand_id' => Yii::t('product', 'Brand'),
67 'categories' => Yii::t('product', 'Categories'), // relation behavior field 71 'categories' => Yii::t('product', 'Categories'), // relation behavior field
  72 + 'category' => Yii::t('product', 'Category'), // relation behavior field
68 ]; 73 ];
69 } 74 }
70 75
@@ -73,17 +78,63 @@ class Product extends \yii\db\ActiveRecord @@ -73,17 +78,63 @@ class Product extends \yii\db\ActiveRecord
73 */ 78 */
74 public function getBrand() 79 public function getBrand()
75 { 80 {
76 - return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_brand_id']); 81 + return $this->hasOne(Brand::className(), ['brand_id' => 'brand_id']);
77 } 82 }
78 83
79 - public function getFullName() 84 + /**
  85 + * @return \yii\db\ActiveQuery
  86 + */
  87 + public function getImage()
  88 + {
  89 + return $this->hasOne(ProductImage::className(), ['product_id' => 'product_id']);
  90 + }
  91 +
  92 + /**
  93 + * @return \yii\db\ActiveQuery
  94 + */
  95 + public function getImages()
80 { 96 {
81 - return $this->brandname .' '. $this->name; 97 + return $this->hasMany(ProductImage::className(), ['product_id' => 'product_id']);
82 } 98 }
83 99
84 - public function getBrandName() 100 + /**
  101 + * @return \yii\db\ActiveQuery
  102 + */
  103 + public function getVariant()
85 { 104 {
86 - return $this->getBrand()->one()->valueRenderHTML; 105 + return $this->hasOne(ProductVariant::className(), ['product_id' => 'product_id']);
  106 + }
  107 +
  108 + public function getVariantPrice() {
  109 + return $this->variant->price;
  110 + }
  111 + /**
  112 + * @return \yii\db\ActiveQuery
  113 + */
  114 + public function getVariants()
  115 + {
  116 + return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id']);
  117 + }
  118 +
  119 + public function setVariants($variants) {
  120 + $this->_variants = $variants;
  121 + }
  122 +
  123 + public function getFullName()
  124 + {
  125 + return $this->brand->name .' '. $this->name;
  126 + }
  127 +
  128 + public function getCategories() {
  129 + return $this->getRelations('product_categories');
  130 + }
  131 +
  132 + public function getCategoriesNames() {
  133 + $result = [];
  134 + foreach($this->categories as $category) {
  135 + $result[] = $category->name;
  136 + }
  137 + return $result;
87 } 138 }
88 139
89 public function getCategory() { 140 public function getCategory() {
@@ -91,8 +142,8 @@ class Product extends \yii\db\ActiveRecord @@ -91,8 +142,8 @@ class Product extends \yii\db\ActiveRecord
91 $categories = $this->getRelations('product_categories'); 142 $categories = $this->getRelations('product_categories');
92 $count = $categories->count(); 143 $count = $categories->count();
93 if ($count == 0) 144 if ($count == 0)
94 - return 'None';  
95 - return $categories->one()->ValueRenderFlash . ($count > 1 ? ' + '. $count : ''); 145 + return;
  146 + return $categories->one();
96 } 147 }
97 148
98 /** 149 /**
@@ -103,4 +154,28 @@ class Product extends \yii\db\ActiveRecord @@ -103,4 +154,28 @@ class Product extends \yii\db\ActiveRecord
103 { 154 {
104 return new ProductQuery(get_called_class()); 155 return new ProductQuery(get_called_class());
105 } 156 }
  157 +
  158 + public function afterSave($insert, $changedAttributes)
  159 + {
  160 + parent::afterSave($insert, $changedAttributes);
  161 +
  162 + $todel = [];
  163 + foreach ($this->variants ? : [] as $_variant) {
  164 + $todel[$_variant->product_variant_id] = $_variant->product_variant_id;
  165 + }
  166 + foreach ($this->_variants as $_variant) {
  167 + if (!empty($_variant['product_variant_id'])) {
  168 + unset($todel[$_variant['product_variant_id']]);
  169 + $model = ProductVariant::findOne($_variant['product_variant_id']);
  170 + } else {
  171 + $model = new ProductVariant();
  172 + }
  173 + $_variant['product_id'] = $this->product_id;
  174 + $model->load(['ProductVariant' => $_variant]);
  175 + $model->save();
  176 + }
  177 + if (!empty($todel)) {
  178 + ProductVariant::deleteAll(['product_variant_id' => $todel]);
  179 + }
  180 + }
106 } 181 }
common/modules/product/models/ProductCategory.php
@@ -26,15 +26,14 @@ class ProductCategory extends Relation @@ -26,15 +26,14 @@ class ProductCategory extends Relation
26 return 'product_category'; 26 return 'product_category';
27 } 27 }
28 28
29 -  
30 /** 29 /**
31 * @inheritdoc 30 * @inheritdoc
32 */ 31 */
33 public function rules() 32 public function rules()
34 { 33 {
35 return [ 34 return [
36 - [['product_id', 'dev_category_id'], 'integer'],  
37 - [['dev_category_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['dev_category_id' => 'tax_option_id']], 35 + [['product_id', 'category_id'], 'integer'],
  36 + [['category_id'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['category_id' => 'category_id']],
38 [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']], 37 [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
39 ]; 38 ];
40 } 39 }
@@ -46,7 +45,7 @@ class ProductCategory extends Relation @@ -46,7 +45,7 @@ class ProductCategory extends Relation
46 { 45 {
47 return [ 46 return [
48 'product_id' => Yii::t('product', 'Product'), 47 'product_id' => Yii::t('product', 'Product'),
49 - 'dev_category_id' => Yii::t('product', 'Category'), 48 + 'category_id' => Yii::t('product', 'Category'),
50 ]; 49 ];
51 } 50 }
52 51
common/modules/product/models/ProductImage.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\models;
  4 +
  5 +use Yii;
  6 +use yii\web\UploadedFile;
  7 +
  8 +/**
  9 + * This is the model class for table "product_image".
  10 + *
  11 + * @property integer $product_image_id
  12 + * @property integer $product_id
  13 + * @property string $image
  14 + * @property string $alt
  15 + * @property string $title
  16 + *
  17 + * @property Product $product
  18 + */
  19 +class ProductImage extends \yii\db\ActiveRecord
  20 +{
  21 + public $image;
  22 + /**
  23 + * @inheritdoc
  24 + */
  25 + public static function tableName()
  26 + {
  27 + return 'product_image';
  28 + }
  29 +
  30 + /**
  31 + * @inheritdoc
  32 + */
  33 + public function rules()
  34 + {
  35 + return [
  36 + [['product_image_id', 'product_id'], 'required'],
  37 + [['product_image_id', 'product_id'], 'integer'],
  38 + [['alt', 'title'], 'string', 'max' => 255],
  39 + [['image'], 'safe'],
  40 + [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
  41 + [['image'], 'file', 'extensions'=>'jpg, gif, png'],
  42 + ];
  43 + }
  44 +
  45 + /**
  46 + * @inheritdoc
  47 + */
  48 + public function attributeLabels()
  49 + {
  50 + return [
  51 + 'product_image_id' => Yii::t('product', 'Product Image ID'),
  52 + 'product_id' => Yii::t('product', 'Product ID'),
  53 + 'image' => Yii::t('product', 'Image'),
  54 + 'alt' => Yii::t('product', 'Alt'),
  55 + 'title' => Yii::t('product', 'Title'),
  56 + ];
  57 + }
  58 +
  59 + /**
  60 + * @return \yii\db\ActiveQuery
  61 + */
  62 + public function getProduct()
  63 + {
  64 + return $this->hasOne(Product::className(), ['product_id' => 'product_id']);
  65 + }
  66 +
  67 + /**
  68 + * @inheritdoc
  69 + * @return ProductImageQuery the active query used by this AR class.
  70 + */
  71 + public static function find()
  72 + {
  73 + return new ProductImageQuery(get_called_class());
  74 + }
  75 +
  76 + /**
  77 + * fetch stored image file name with complete path
  78 + * @return string
  79 + */
  80 + public function getImageFile()
  81 + {
  82 + return isset($this->image) ? Yii::$app->params['uploadPath'] . $this->image : null;
  83 + }
  84 +
  85 + /**
  86 + * fetch stored image url
  87 + * @return string
  88 + */
  89 + public function getImageUrl()
  90 + {
  91 + // return a default image placeholder if your source image is not found
  92 + $image = isset($this->image) ? $this->image : 'default.jpg';
  93 + return Yii::$app->params['uploadUrl'] . $image;
  94 + }
  95 +
  96 + /**
  97 + * Process upload of image
  98 + *
  99 + * @return mixed the uploaded image instance
  100 + */
  101 + public function uploadImage() {
  102 + // get the uploaded file instance. for multiple file uploads
  103 + // the following data will return an array (you may need to use
  104 + // getInstances method)
  105 + $image = UploadedFile::getInstance($this, 'image');
  106 +
  107 + // if no image was uploaded abort the upload
  108 + if (empty($image)) {
  109 + return false;
  110 + }
  111 +
  112 + // store the source file name
  113 + $this->filename = $image->name;
  114 + $ext = end((explode(".", $image->name)));
  115 +
  116 + // generate a unique file name
  117 + $this->image = Yii::$app->security->generateRandomString().".{$ext}";
  118 +
  119 + // the uploaded image instance
  120 + return $image;
  121 + }
  122 +
  123 + /**
  124 + * Process deletion of image
  125 + *
  126 + * @return boolean the status of deletion
  127 + */
  128 + public function deleteImage() {
  129 + $file = $this->getImageFile();
  130 +
  131 + // check if file exists on server
  132 + if (empty($file) || !file_exists($file)) {
  133 + return false;
  134 + }
  135 +
  136 + // check if uploaded file can be deleted on server
  137 + if (!unlink($file)) {
  138 + return false;
  139 + }
  140 +
  141 + // if deletion successful, reset your file attributes
  142 + $this->image = null;
  143 + $this->filename = null;
  144 +
  145 + return true;
  146 + }
  147 +}
common/modules/product/models/ProductImageQuery.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\models;
  4 +
  5 +/**
  6 + * This is the ActiveQuery class for [[ProductImage]].
  7 + *
  8 + * @see ProductImage
  9 + */
  10 +class ProductImageQuery extends \yii\db\ActiveQuery
  11 +{
  12 + /*public function active()
  13 + {
  14 + return $this->andWhere('[[status]]=1');
  15 + }*/
  16 +
  17 + /**
  18 + * @inheritdoc
  19 + * @return ProductImage[]|array
  20 + */
  21 + public function all($db = null)
  22 + {
  23 + return parent::all($db);
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + * @return ProductImage|array|null
  29 + */
  30 + public function one($db = null)
  31 + {
  32 + return parent::one($db);
  33 + }
  34 +}
common/modules/product/models/ProductQuery.php
@@ -31,4 +31,15 @@ class ProductQuery extends \yii\db\ActiveQuery @@ -31,4 +31,15 @@ class ProductQuery extends \yii\db\ActiveQuery
31 { 31 {
32 return parent::one($db); 32 return parent::one($db);
33 } 33 }
  34 +
  35 + /**
  36 + * Select category by alias
  37 + * @param $slug
  38 + * @return $this
  39 + */
  40 + public function byAlias($alias)
  41 + {
  42 + $this->andFilterWhere(['alias' => $alias]);
  43 + return $this;
  44 + }
34 } 45 }
common/modules/product/models/ProductSearch.php
@@ -67,4 +67,16 @@ class ProductSearch extends Product @@ -67,4 +67,16 @@ class ProductSearch extends Product
67 67
68 return $dataProvider; 68 return $dataProvider;
69 } 69 }
  70 +
  71 + public static function findByAlias($alias) {
  72 + /** @var ProductQuery $query */
  73 + $query = Category::find();
  74 + $query->byAlias($alias);
  75 + if (($model = $query->one()) !== null) {
  76 + return $model;
  77 + } else {
  78 + throw new NotFoundHttpException('The requested product does not exist.');
  79 + }
  80 + }
  81 +
70 } 82 }
common/modules/product/models/ProductVariant.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\models;
  4 +
  5 +use Yii;
  6 +
  7 +/**
  8 + * This is the model class for table "product_variant".
  9 + *
  10 + * @property integer $product_variant_id
  11 + * @property integer $product_id
  12 + * @property string $name
  13 + * @property string $sku
  14 + * @property double $price
  15 + * @property double $price_old
  16 + * @property double $stock
  17 + * @property integer $product_unit_id
  18 + *
  19 + * @property ProductUnit $productUnit
  20 + */
  21 +class ProductVariant extends \yii\db\ActiveRecord
  22 +{
  23 + /**
  24 + * @inheritdoc
  25 + */
  26 + public static function tableName()
  27 + {
  28 + return 'product_variant';
  29 + }
  30 +
  31 + /**
  32 + * @inheritdoc
  33 + */
  34 + public function rules()
  35 + {
  36 + return [
  37 + [['product_id', 'name', 'sku', 'product_unit_id'], 'required'],
  38 + [['product_id', 'product_unit_id'], 'integer'],
  39 + [['price', 'price_old', 'stock'], 'number'],
  40 + [['name', 'sku'], 'string', 'max' => 255],
  41 + [['product_unit_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductUnit::className(), 'targetAttribute' => ['product_unit_id' => 'product_unit_id']],
  42 + ];
  43 + }
  44 +
  45 + /**
  46 + * @inheritdoc
  47 + */
  48 + public function attributeLabels()
  49 + {
  50 + return [
  51 + 'product_variant_id' => Yii::t('product', 'Product Variant ID'),
  52 + 'product_id' => Yii::t('product', 'Product ID'),
  53 + 'name' => Yii::t('product', 'Name'),
  54 + 'sku' => Yii::t('product', 'Sku'),
  55 + 'price' => Yii::t('product', 'Price'),
  56 + 'price_old' => Yii::t('product', 'Price Old'),
  57 + 'stock' => Yii::t('product', 'Stock'),
  58 + 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
  59 + ];
  60 + }
  61 +
  62 + /**
  63 + * @return \yii\db\ActiveQuery
  64 + */
  65 + public function getProductUnit()
  66 + {
  67 + return $this->hasOne(ProductUnit::className(), ['product_unit_id' => 'product_unit_id']);
  68 + }
  69 +
  70 + /**
  71 + * @inheritdoc
  72 + * @return ProductVariantQuery the active query used by this AR class.
  73 + */
  74 + public static function find()
  75 + {
  76 + return new ProductVariantQuery(get_called_class());
  77 + }
  78 +}
common/modules/product/models/ProductVariantQuery.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\product\models;
  4 +
  5 +/**
  6 + * This is the ActiveQuery class for [[ProductVariant]].
  7 + *
  8 + * @see ProductVariant
  9 + */
  10 +class ProductVariantQuery extends \yii\db\ActiveQuery
  11 +{
  12 + /*public function active()
  13 + {
  14 + return $this->andWhere('[[status]]=1');
  15 + }*/
  16 +
  17 + /**
  18 + * @inheritdoc
  19 + * @return ProductVariant[]|array
  20 + */
  21 + public function all($db = null)
  22 + {
  23 + return parent::all($db);
  24 + }
  25 +
  26 + /**
  27 + * @inheritdoc
  28 + * @return ProductVariant|array|null
  29 + */
  30 + public function one($db = null)
  31 + {
  32 + return parent::one($db);
  33 + }
  34 +}
common/modules/product/views/manage/_form.php
@@ -5,6 +5,9 @@ use yii\widgets\ActiveForm; @@ -5,6 +5,9 @@ use yii\widgets\ActiveForm;
5 use yii\helpers\ArrayHelper; 5 use yii\helpers\ArrayHelper;
6 use common\components\artboxtree\ArtboxTreeHelper; 6 use common\components\artboxtree\ArtboxTreeHelper;
7 use common\modules\product\helpers\ProductHelper; 7 use common\modules\product\helpers\ProductHelper;
  8 +use kartik\file\FileInput;
  9 +use unclead\widgets\MultipleInput;
  10 +use unclead\widgets\MultipleInputColumn;
8 11
9 /* @var $this yii\web\View */ 12 /* @var $this yii\web\View */
10 /* @var $model common\modules\product\models\Product */ 13 /* @var $model common\modules\product\models\Product */
@@ -17,23 +20,76 @@ use common\modules\product\helpers\ProductHelper; @@ -17,23 +20,76 @@ use common\modules\product\helpers\ProductHelper;
17 20
18 <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?> 21 <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
19 22
20 - <?= $form->field($model, 'tax_brand_id')->dropDownList(  
21 - ArrayHelper::map(ProductHelper::getBrands()->all(), 'tax_option_id', 'ValueRenderFlash'), 23 + <?= $form->field($model, 'brand_id')->dropDownList(
  24 + ArrayHelper::map(ProductHelper::getBrands()->all(), 'brand_id', 'name'),
22 [ 25 [
23 'prompt' => Yii::t('product', 'Select brand') 26 'prompt' => Yii::t('product', 'Select brand')
24 ] 27 ]
25 ) ?> 28 ) ?>
26 - <?php  
27 -// var_dump($model->categories);  
28 - ?> 29 +
29 <?= $form->field($model, 'categories')->dropDownList( 30 <?= $form->field($model, 'categories')->dropDownList(
30 - ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'tax_option_id', 'ValueRenderFlash'), 31 + ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'category_id', 'name'),
31 [ 32 [
32 // 'prompt' => Yii::t('product', 'Select category'), 33 // 'prompt' => Yii::t('product', 'Select category'),
33 'multiple' => true 34 'multiple' => true
34 ] 35 ]
35 ) ?> 36 ) ?>
36 37
  38 + <?php /*= $form->field($model, 'images[]')->widget(FileInput::classname(), [
  39 + 'options' => [
  40 + 'accept' => 'image/*',
  41 + 'multiple' => true,
  42 + ],
  43 + 'pluginOptions' => [
  44 +// 'uploadUrl' => \yii\helpers\Url::to(['/site/file-upload']),
  45 + ]
  46 + ]);
  47 + */?>
  48 +
  49 + <?= $form->field($model, 'variants')->widget(MultipleInput::className(), [
  50 + 'columns' => [
  51 + [
  52 + 'name' => 'product_variant_id',
  53 + 'type' => MultipleInputColumn::TYPE_HIDDEN_INPUT,
  54 + ],
  55 + [
  56 + 'name' => 'name',
  57 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  58 + 'title' => 'Name',
  59 + ],
  60 + [
  61 + 'name' => 'sku',
  62 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  63 + 'title' => 'SKU',
  64 + ],
  65 + [
  66 + 'name' => 'price',
  67 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  68 + 'title' => 'Price',
  69 + ],
  70 + [
  71 + 'name' => 'price_old',
  72 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  73 + 'title' => 'Old Price',
  74 + ],
  75 + [
  76 + 'name' => 'product_unit_id',
  77 + 'type' => MultipleInputColumn::TYPE_DROPDOWN,
  78 + 'title' => 'Unit',
  79 + 'items' => ArrayHelper::map(\common\modules\product\models\ProductUnit::find()->all(), 'product_unit_id', 'name'),
  80 + ],
  81 + [
  82 + 'name' => 'stock',
  83 + 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
  84 + 'title' => 'Stock',
  85 + 'options' => [
  86 + 'placeholder' => '∞'
  87 + ],
  88 + ],
  89 + ],
  90 + ]);
  91 + ?>
  92 +
37 <div class="form-group"> 93 <div class="form-group">
38 <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 94 <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
39 </div> 95 </div>
common/modules/product/views/manage/_search.php
@@ -17,7 +17,7 @@ use yii\widgets\ActiveForm; @@ -17,7 +17,7 @@ use yii\widgets\ActiveForm;
17 17
18 <?= $form->field($model, 'name') ?> 18 <?= $form->field($model, 'name') ?>
19 19
20 - <?= $form->field($model, 'tax_brand_id') ?> 20 + <?= $form->field($model, 'brand_id') ?>
21 21
22 <?= $form->field($model, 'product_id') ?> 22 <?= $form->field($model, 'product_id') ?>
23 23
common/modules/product/views/manage/index.php
@@ -22,11 +22,10 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title; @@ -22,11 +22,10 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
22 'filterModel' => $searchModel, 22 'filterModel' => $searchModel,
23 'columns' => [ 23 'columns' => [
24 ['class' => 'yii\grid\SerialColumn'], 24 ['class' => 'yii\grid\SerialColumn'],
25 -  
26 -// 'product_id',  
27 - 'fullname',  
28 - 'brandname',  
29 - 'category', 25 + 'product_id',
  26 + 'name',
  27 + 'brand.name',
  28 + 'category.name',
30 29
31 ['class' => 'yii\grid\ActionColumn'], 30 ['class' => 'yii\grid\ActionColumn'],
32 ], 31 ],
common/modules/product/views/manage/view.php
@@ -28,9 +28,11 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title; @@ -28,9 +28,11 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
28 <?= DetailView::widget([ 28 <?= DetailView::widget([
29 'model' => $model, 29 'model' => $model,
30 'attributes' => [ 30 'attributes' => [
31 - 'name',  
32 - 'tax_brand_id',  
33 'product_id', 31 'product_id',
  32 + 'name',
  33 + 'fullname',
  34 + 'brand.name',
  35 + 'category.name',
34 ], 36 ],
35 ]) ?> 37 ]) ?>
36 38
common/modules/product/widgets/views/submenu.php
1 <div class="menu_item"> 1 <div class="menu_item">
2 - <?= \yii\helpers\Html::a($rootCategory->name, ['product/category', 'alias' => $rootCategory->alias], ['class' => 'submenu_button '. $rootClass])?> 2 + <?= \yii\helpers\Html::a($rootCategory->name, ['catalog/category', 'alias' => $rootCategory->alias], ['class' => 'submenu_button '. $rootClass])?>
3 <div class="submenu"> 3 <div class="submenu">
4 <ul class="categories"> 4 <ul class="categories">
5 <li class="sub_cat"><span>Популярные категории</span> 5 <li class="sub_cat"><span>Популярные категории</span>
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <div class="sub_cat_content"> 7 <div class="sub_cat_content">
8 <div class="content_items"> 8 <div class="content_items">
9 <?php foreach($populary as $_item) :?> 9 <?php foreach($populary as $_item) :?>
10 - <div class="content_item"><a href="<?= \yii\helpers\Url::to(['product/category', 'alias' => $_item->alias])?>"> 10 + <div class="content_item"><a href="<?= \yii\helpers\Url::to(['catalog/category', 'alias' => $_item->alias])?>">
11 <div valign="top" class="picture"><img valign="top" src="<?= $_item->image?>"></div> 11 <div valign="top" class="picture"><img valign="top" src="<?= $_item->image?>"></div>
12 <div class="title"><?= $_item->name?></div> 12 <div class="title"><?= $_item->name?></div>
13 </a></div> 13 </a></div>
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 <div class="sub_cat_content"> 23 <div class="sub_cat_content">
24 <div class="content_items"> 24 <div class="content_items">
25 <?php foreach($item['children'] as $_item) :?> 25 <?php foreach($item['children'] as $_item) :?>
26 - <div class="content_item"><a href="<?= \yii\helpers\Url::to(['/catalog/' .$_item['item']->alias])?>"> 26 + <div class="content_item"><a href="<?= \yii\helpers\Url::to(['/catalog/category', 'alias' => $_item['item']->alias])?>">
27 <div valign="top" class="picture"><img valign="top" src="<?= $_item['item']->image?>"></div> 27 <div valign="top" class="picture"><img valign="top" src="<?= $_item['item']->image?>"></div>
28 <div class="title"><?= $_item['item']->name?></div> 28 <div class="title"><?= $_item['item']->name?></div>
29 </a></div> 29 </a></div>
common/modules/relation/relationQueryTrait.php
@@ -21,7 +21,13 @@ trait relationQueryTrait { @@ -21,7 +21,13 @@ trait relationQueryTrait {
21 return self::$model; 21 return self::$model;
22 } 22 }
23 23
24 - public function getRelations($relationKey) { 24 + /*public function getRelations($relation) {
  25 + $model = $this->getModel();
25 26
26 - } 27 + $relation = $model->_getRelation($relation);
  28 + return
  29 + $model->owner
  30 + ->hasMany($relation['outer']['model'], [$relation['outer']['key'] => $relation['outer']['linked_key']])
  31 + ->viaTable($relation['linked_table'], [$relation['inner']['linked_key'] => $relation['inner']['key']]);
  32 + }*/
27 } 33 }
28 \ No newline at end of file 34 \ No newline at end of file
common/modules/rubrication/Module.php
@@ -8,7 +8,7 @@ use Yii; @@ -8,7 +8,7 @@ use Yii;
8 */ 8 */
9 class Module extends \yii\base\Module 9 class Module extends \yii\base\Module
10 { 10 {
11 - public $types; 11 + public $types = [];
12 /** 12 /**
13 * @inheritdoc 13 * @inheritdoc
14 */ 14 */
@@ -22,7 +22,5 @@ class Module extends \yii\base\Module @@ -22,7 +22,5 @@ class Module extends \yii\base\Module
22 public function init() 22 public function init()
23 { 23 {
24 parent::init(); 24 parent::init();
25 -  
26 - // custom initialization code goes here  
27 } 25 }
28 } 26 }
common/modules/rubrication/models/TaxGroup.php
@@ -35,6 +35,12 @@ class TaxGroup extends \yii\db\ActiveRecord @@ -35,6 +35,12 @@ class TaxGroup extends \yii\db\ActiveRecord
35 // 'tax_option_to_group' => 'entity2', 35 // 'tax_option_to_group' => 'entity2',
36 ] 36 ]
37 ], 37 ],
  38 + 'slug' => [
  39 + 'class' => 'common\behaviors\Slug',
  40 + 'in_attribute' => 'name',
  41 + 'out_attribute' => 'alias',
  42 + 'translit' => true
  43 + ],
38 ]; 44 ];
39 } 45 }
40 46
@@ -52,7 +58,7 @@ class TaxGroup extends \yii\db\ActiveRecord @@ -52,7 +58,7 @@ class TaxGroup extends \yii\db\ActiveRecord
52 public function rules() 58 public function rules()
53 { 59 {
54 return [ 60 return [
55 - [['alias', 'name', 'module'], 'required'], 61 + [['name', 'module'], 'required'],
56 [['description', 'settings'], 'string'], 62 [['description', 'settings'], 'string'],
57 [['hierarchical'], 'boolean'], 63 [['hierarchical'], 'boolean'],
58 [['alias', 'module'], 'string', 'max' => 50], 64 [['alias', 'module'], 'string', 'max' => 50],
common/modules/rubrication/models/TaxOption.php
@@ -53,13 +53,6 @@ class TaxOption extends \yii\db\ActiveRecord @@ -53,13 +53,6 @@ class TaxOption extends \yii\db\ActiveRecord
53 ]; 53 ];
54 } 54 }
55 55
56 - public function events() {  
57 - return $this->events();  
58 - return [  
59 -// ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',  
60 - ];  
61 - }  
62 -  
63 /** 56 /**
64 * @inheritdoc 57 * @inheritdoc
65 */ 58 */
@@ -226,6 +219,7 @@ class TaxOption extends \yii\db\ActiveRecord @@ -226,6 +219,7 @@ class TaxOption extends \yii\db\ActiveRecord
226 219
227 private function getValueModelName() { 220 private function getValueModelName() {
228 $group = $this->getTaxGroup()->one(); 221 $group = $this->getTaxGroup()->one();
  222 +// var_dump($group);exit;
229 $valueClass = '\common\modules\rubrication\models\TaxValue'. ucfirst($group->module); 223 $valueClass = '\common\modules\rubrication\models\TaxValue'. ucfirst($group->module);
230 return class_exists($valueClass) ? $valueClass : FALSE; 224 return class_exists($valueClass) ? $valueClass : FALSE;
231 } 225 }
console/migrations/m160323_234304_product_image.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +class m160323_234304_product_image extends Migration
  6 +{
  7 + public function up()
  8 + {
  9 + $tableOptions = null;
  10 + if ($this->db->driverName === 'mysql') {
  11 + // Only for MySQL
  12 + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
  13 +
  14 + // @todo https://habrahabr.ru/post/138947/
  15 + } elseif ($this->db->driverName === 'pgsql') {
  16 + // Only for PostgreSQL
  17 + // @todo use intarray field for tax_options
  18 + }
  19 +
  20 + $this->createTable('{{%product_image}}', [
  21 + 'product_image_id' => $this->integer()->notNull(),
  22 + 'product_id' => $this->integer()->notNull(),
  23 + 'image' => $this->string(255),
  24 + 'alt' => $this->string(255),
  25 + 'title' => $this->string(255),
  26 + ], $tableOptions);
  27 + $this->addForeignKey('product_image_product_fkey', 'product_image', 'product_id', 'product', 'product_id', 'CASCADE', 'CASCADE');
  28 + }
  29 +
  30 + public function down()
  31 + {
  32 + $this->dropTable('{{%product_image}}');
  33 + }
  34 +
  35 + /*
  36 + // Use safeUp/safeDown to run migration code within a transaction
  37 + public function safeUp()
  38 + {
  39 + }
  40 +
  41 + public function safeDown()
  42 + {
  43 + }
  44 + */
  45 +}
frontend/controllers/CatalogController.php
@@ -2,9 +2,17 @@ @@ -2,9 +2,17 @@
2 2
3 namespace frontend\controllers; 3 namespace frontend\controllers;
4 4
  5 +use common\modules\product\models\Brand;
5 use common\modules\product\models\Category; 6 use common\modules\product\models\Category;
6 use common\modules\product\models\CategorySearch; 7 use common\modules\product\models\CategorySearch;
7 use common\modules\product\models\Product; 8 use common\modules\product\models\Product;
  9 +use common\modules\product\models\ProductCategory;
  10 +use common\modules\product\models\ProductSearch;
  11 +use common\modules\product\models\ProductVariant;
  12 +use yii\data\ActiveDataProvider;
  13 +use yii\data\Pagination;
  14 +use yii\data\Sort;
  15 +use yii\db\ActiveQuery;
8 use yii\web\HttpException; 16 use yii\web\HttpException;
9 17
10 class CatalogController extends \yii\web\Controller 18 class CatalogController extends \yii\web\Controller
@@ -12,6 +20,9 @@ class CatalogController extends \yii\web\Controller @@ -12,6 +20,9 @@ class CatalogController extends \yii\web\Controller
12 public function actionCategory($alias) 20 public function actionCategory($alias)
13 { 21 {
14 $category = CategorySearch::findByAlias($alias); 22 $category = CategorySearch::findByAlias($alias);
  23 + if (empty($category->category_id)) {
  24 + throw new HttpException(404 ,'Page not found');
  25 + }
15 if ($category->depth < 2) { 26 if ($category->depth < 2) {
16 return $this->render( 27 return $this->render(
17 'categories', 28 'categories',
@@ -20,11 +31,62 @@ class CatalogController extends \yii\web\Controller @@ -20,11 +31,62 @@ class CatalogController extends \yii\web\Controller
20 ] 31 ]
21 ); 32 );
22 } else { 33 } else {
  34 +// $products = $category->getRelations('product_categories')->all();
  35 +
  36 + $per_page = 24;
  37 +
  38 + $sort = new Sort([
  39 + 'attributes' => [
  40 + 'name' => [
  41 + 'asc' => ['name' => SORT_ASC],
  42 + 'desc' => ['name' => SORT_DESC],
  43 + 'default' => SORT_DESC,
  44 + 'label' => 'имени',
  45 + ],
  46 + 'price' => [
  47 + 'asc' => [ProductVariant::tableName() .'.price' => SORT_ASC],
  48 + 'desc' => [ProductVariant::tableName() .'.price' => SORT_DESC],
  49 + 'default' => SORT_DESC,
  50 + 'label' => 'цене',
  51 + ],
  52 + ],
  53 + ]);
  54 + /** @var ActiveQuery $query */
  55 + $query = $category->getRelations('product_categories')
  56 + ->joinWith([
  57 + 'variants'
  58 + ]);
  59 + $pages = new Pagination(['totalCount' => $query->count(), 'pageSize' => $per_page]);
  60 + $count = $query->count();
  61 +
  62 +// $priceQuery = clone $query;
  63 + $priceMin = $query->min(ProductVariant::tableName() .'.price');
  64 + $priceMax = $query->max(ProductVariant::tableName() .'.price');
  65 +
  66 + $query->offset($pages->offset)
  67 + ->orderBy($sort->orders)
  68 + ->limit($pages->limit);
  69 + $products = $query->all();
  70 +
  71 + $brandsQuery = Brand::find()->innerJoinWith('products')->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. Product::tableName() .'.product_id')->where([
  72 + ProductCategory::tableName() .'.category_id' => $category->category_id
  73 + ])->groupBy(Brand::tableName() .'.brand_id');
  74 + $brands = $brandsQuery->all();
  75 + $brands_count = $brandsQuery->count();
23 76
24 return $this->render( 77 return $this->render(
25 'products', 78 'products',
26 [ 79 [
27 'category' => $category, 80 'category' => $category,
  81 + 'products' => $products,
  82 + 'product_count' => $count,
  83 + 'sort' => $sort,
  84 + 'pages' => $pages,
  85 + 'per_page' => $per_page,
  86 + 'priceMin' => $priceMin,
  87 + 'priceMax' => $priceMax,
  88 + 'brands' => $brands,
  89 + 'brands_count' => $brands_count,
28 ] 90 ]
29 ); 91 );
30 } 92 }
@@ -32,10 +94,9 @@ class CatalogController extends \yii\web\Controller @@ -32,10 +94,9 @@ class CatalogController extends \yii\web\Controller
32 94
33 public function actionProduct($alias) 95 public function actionProduct($alias)
34 { 96 {
35 - $product = Product::find()->where('like', ['alias' => $alias]); 97 + $product = ProductSearch::findByAlias($alias);
36 if (empty($product->product_id)) { 98 if (empty($product->product_id)) {
37 -// throw new HttpException(404 ,'Page not found');  
38 -// return $this->redirect('/', 301); 99 + throw new HttpException(404 ,'Page not found');
39 } 100 }
40 return $this->render('product'); 101 return $this->render('product');
41 } 102 }
frontend/views/catalog/product_item.php 0 → 100644
  1 +<?php
  2 +/** @var \common\modules\product\models\Product $product */
  3 +?>
  4 +<div class="item" data-id="<?= $product->product_id?>">
  5 + <!--<div class="new">АКЦИЯ</div>
  6 + <div class="top">Toп</div>-->
  7 + <a href="#" class="item_link"><div class="pic"><img src="/images/items/01.jpg"></div>
  8 + <div class="title_item"><?= $product->name?></div></a>
  9 + <div class="brand">Бренд: <span><?= $product->brand->name?></span></div>
  10 + <div class="type"><?= implode(', ', $product->categoriesNames)?></div>
  11 + <div class="price"><?= $product->variant->price?> <span>грн.</span></div>
  12 + <button class="basket_add_but" data-id="<?= $product->variant->product_variant_id?>">в корзину</button>
  13 + <a href="#" class="compare_add_but" data-id="<?= $product->product_id?>"><span>добавить к сравнению</span></a>
  14 + <img class="item_bottom_img" src="/images/nc_item_bottom.png" alt="">
  15 +</div>
0 \ No newline at end of file 16 \ No newline at end of file
frontend/views/catalog/products.php
@@ -6,40 +6,434 @@ $this-&gt;title = $category-&gt;name; @@ -6,40 +6,434 @@ $this-&gt;title = $category-&gt;name;
6 foreach($category->getParents()->all() as $parent) { 6 foreach($category->getParents()->all() as $parent) {
7 $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'alias' => $parent->alias]]; 7 $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'alias' => $parent->alias]];
8 } 8 }
9 -$this->params['breadcrumbs'][] = $this->title; 9 +$this->params['breadcrumbs'][] = $category->name;
10 ?> 10 ?>
11 -<h1 class="category_page_main_title"><?= $this->title ?></h1>  
12 -  
13 -<div class="category_wrap">  
14 -  
15 - <div class="category_wrap_3_colum"><!-- 3 colons for items ================================== 1rst colum -->  
16 -  
17 - <?php foreach($category->getAllChildrenTree(2) as $category) :?>  
18 - <div class="wrap">  
19 - <div class="cat_li_cont">  
20 - <?php if (!empty($category['item']->image)) :?>  
21 - <img src="<?= $category['item']->image?>" alt="<?= $category['item']->name?>">  
22 - <?php else :?>  
23 - <img src="/images/category/1.png" alt="">  
24 - <?php endif;?>  
25 - <div class="desc"><?= $category['item']->name?><!-- (133)--></div>  
26 - <?php if(!empty($category['children'])) :?>  
27 - <span class="arrow"></span>  
28 - <?php endif?>  
29 - </div>  
30 - <?php if(!empty($category['children'])) :?>  
31 - <div class="cat_li_sub_ul">  
32 - <ul>  
33 - <?php foreach($category['children'] as $_category) :?>  
34 - <li><a href="<?= \yii\helpers\Url::to(['catalog/category', 'alias' => $_category['item']->alias])?>"><?= $_category['item']->name?><!-- (18)--></a></li>  
35 - <?php endforeach?>  
36 - </ul> 11 +<script type="text/javascript">
  12 + $(document).ready(function() {
  13 + // price rangeslider (filter price slider)
  14 + $("#price_interval").ionRangeSlider({
  15 + type: "double",
  16 + min: <?= $priceMin?>,
  17 + max: <?= $priceMax?>,
  18 + from: <?= $priceMin?>,
  19 + to: <?= $priceMax?>,
  20 + grid: false
  21 + });
  22 + });
  23 +</script>
  24 +<div class="w_960">
  25 + <!-- side bar with all filters -->
  26 + <div class="cat_p_filter_bar">
  27 + <div class="title">ФИЛЬТРЫ</div>
  28 + <div class="filter_list">
  29 + <form action="#" name="filter_catalog_page_form">
  30 + <ul>
  31 + <li>Цена:
  32 + <div class="arrow"><img src="/images/head_up.png" alt=""></i></div>
  33 + <div class="price_filter first_price_li">
  34 + <div class="price_slider">
  35 + <input type="text" id="price_interval" name="price_interval" value="" />
  36 + </div>
  37 + <!--<div class="checkbox">
  38 + <label><input type="checkbox" name="venecia" value="0" /></label>
  39 + <a href="#">Акции</a>
  40 + </div>
  41 + <div class="checkbox">
  42 + <label><input type="checkbox" name="venecia" value="0" /></label>
  43 + <a href="#">Товар в наличии</a>
  44 + </div>
  45 + <div class="checkbox">
  46 + <label><input type="checkbox" name="venecia" value="0" /></label>
  47 + <a href="#">Хит продаж</a>
  48 + </div>-->
  49 + </div>
  50 + </li>
  51 +
  52 + <?php if ($brands_count) :?>
  53 + <li>Бренд
  54 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  55 + <div class="price_filter">
  56 + <?php foreach($brands as $brand) :?>
  57 + <div class="checkbox">
  58 + <label><input type="checkbox" name="think" value="ruuki" /></label>
  59 + <a href="<?= \yii\helpers\Url::to(['catalog/brand', 'alias' => $brand->alias])?>"><?= $brand->name?> (<?= $brand->getProducts()->count()?>)</a>
  60 + </div>
  61 + <?php endforeach?>
  62 + <!--<div class="checkbox see_all">
  63 + <i class="fa fa-plus-circle"></i>
  64 + <a href="#">посмотреть все</a>
  65 + </div>-->
  66 + </div>
  67 + </li>
  68 + <?php endif?>
  69 +
  70 + <div class="title_2">ПОДБОР ПО ПАРАМЕТРАМ</div>
  71 +
  72 + <li>Толщина металла, мм
  73 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  74 + <div class="price_filter">
  75 + <div class="checkbox">
  76 + <label><input type="checkbox" name="venecia" value="0" /></label>
  77 + <a href="#">0,4</a>
  78 + </div>
  79 + <div class="checkbox">
  80 + <label><input type="checkbox" name="venecia" value="0" /></label>
  81 + <a href="#">0,45</a>
  82 + </div>
  83 + <div class="checkbox">
  84 + <label><input type="checkbox" name="venecia" value="0" /></label>
  85 + <a href="#">0,5</a>
  86 + </div>
  87 + </div>
  88 + </li>
  89 +
  90 + <li>Покрытие
  91 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  92 + <div class="price_filter">
  93 + <div class="checkbox">
  94 + <label><input type="checkbox" name="venecia" value="0" /></label>
  95 + <a href="#">RUUKI(3)</a>
  96 + </div>
  97 + <div class="checkbox">
  98 + <label><input type="checkbox" name="venecia" value="0" /></label>
  99 + <a href="#">Venecia(10)</a>
  100 + </div>
  101 + </div>
  102 + </li>
  103 +
  104 + <li>Металл
  105 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  106 + <div class="price_filter">
  107 + <div class="checkbox">
  108 + <label><input type="checkbox" name="venecia" value="0" /></label>
  109 + <a href="#">RUUKI(3)</a>
  110 + </div>
  111 + <div class="checkbox">
  112 + <label><input type="checkbox" name="venecia" value="0" /></label>
  113 + <a href="#">Venecia(10)</a>
  114 + </div>
  115 + </div>
  116 + </li>
  117 +
  118 + <li>Производитель
  119 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  120 + <div class="price_filter">
  121 + <div class="checkbox">
  122 + <label><input type="checkbox" name="venecia" value="0" /></label>
  123 + <a href="#">RUUKI(3)</a>
  124 + </div>
  125 + <div class="checkbox">
  126 + <label><input type="checkbox" name="venecia" value="0" /></label>
  127 + <a href="#">Venecia(10)</a>
  128 + </div>
  129 + </div>
  130 + </li>
  131 +
  132 + <li>Профиль
  133 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  134 + <div class="price_filter">
  135 + <div class="checkbox">
  136 + <label><input type="checkbox" name="venecia" value="0" /></label>
  137 + <a href="#">RUUKI(3)</a>
  138 + </div>
  139 + <div class="checkbox">
  140 + <label><input type="checkbox" name="venecia" value="0" /></label>
  141 + <a href="#">Venecia(10)</a>
  142 + </div>
  143 + </div>
  144 + </li>
  145 +
  146 + <li>Вес 1 м2 на кг
  147 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  148 + <div class="price_filter">
  149 + <div class="checkbox">
  150 + <label><input type="checkbox" name="venecia" value="0" /></label>
  151 + <a href="#">RUUKI(3)</a>
  152 + </div>
  153 + <div class="checkbox">
  154 + <label><input type="checkbox" name="venecia" value="0" /></label>
  155 + <a href="#">Venecia(10)</a>
  156 + </div>
  157 + </div>
  158 + </li>
  159 +
  160 + <li><span class="width_li_filter">Общая высота профиля, мм</span>
  161 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  162 + <div class="price_filter">
  163 + <div class="checkbox">
  164 + <label><input type="checkbox" name="venecia" value="0" /></label>
  165 + <a href="#">RUUKI(3)</a>
  166 + </div>
  167 + <div class="checkbox">
  168 + <label><input type="checkbox" name="venecia" value="0" /></label>
  169 + <a href="#">Venecia(10)</a>
  170 + </div>
  171 + </div>
  172 + </li>
  173 +
  174 + <li><span>Общая ширина, мм</span>
  175 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  176 + <div class="price_filter">
  177 + <div class="checkbox">
  178 + <label><input type="checkbox" name="venecia" value="0" /></label>
  179 + <a href="#">RUUKI(3)</a>
  180 + </div>
  181 + <div class="checkbox">
  182 + <label><input type="checkbox" name="venecia" value="0" /></label>
  183 + <a href="#">Venecia(10)</a>
  184 + </div>
  185 + </div>
  186 + </li>
  187 +
  188 + <li>Шаг волны, мм
  189 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  190 + <div class="price_filter">
  191 + <div class="checkbox">
  192 + <label><input type="checkbox" name="venecia" value="0" /></label>
  193 + <a href="#">RUUKI(3)</a>
  194 + </div>
  195 + <div class="checkbox">
  196 + <label><input type="checkbox" name="venecia" value="0" /></label>
  197 + <a href="#">Venecia(10)</a>
  198 + </div>
  199 + </div>
  200 + </li>
  201 +
  202 + <li>Полезная ширина, мм
  203 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  204 + <div class="price_filter">
  205 + <div class="checkbox">
  206 + <label><input type="checkbox" name="venecia" value="0" /></label>
  207 + <a href="#">RUUKI(3)</a>
  208 + </div>
  209 + <div class="checkbox">
  210 + <label><input type="checkbox" name="venecia" value="0" /></label>
  211 + <a href="#">Venecia(10)</a>
  212 + </div>
  213 + </div>
  214 + </li>
  215 +
  216 + <li><span class="width_li_filter">Количества цинка, г/м2</span>
  217 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  218 + <div class="price_filter">
  219 + <div class="checkbox">
  220 + <label><input type="checkbox" name="venecia" value="0" /></label>
  221 + <a href="#">RUUKI(3)</a>
  222 + </div>
  223 + <div class="checkbox">
  224 + <label><input type="checkbox" name="venecia" value="0" /></label>
  225 + <a href="#">Venecia(10)</a>
  226 + </div>
  227 + </div>
  228 + </li>
  229 +
  230 + <li>Гарантия
  231 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  232 + <div class="price_filter">
  233 + <div class="checkbox">
  234 + <label><input type="checkbox" name="venecia" value="0" /></label>
  235 + <a href="#">RUUKI(3)</a>
  236 + </div>
  237 + <div class="checkbox">
  238 + <label><input type="checkbox" name="venecia" value="0" /></label>
  239 + <a href="#">Venecia(10)</a>
  240 + </div>
  241 + </div>
  242 + </li>
  243 +
  244 + </ul>
  245 +
  246 + <div class="filter_accept_bloc">
  247 + <button type="submit" class="filter_accept_btn">применить</button>
  248 + <a href="#" class="form_checkbox_reset">сбросить фильтры</a>
37 </div> 249 </div>
  250 + </form>
  251 + <!--<div class="product_list">
  252 + <h2 class="title">КАТАЛОГ ТОВАРОВ</h2>
  253 + <ul>
  254 + <li>Битумная черепица
  255 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  256 + <div class="price_filter">
  257 + <a href="#">RUUKI</a>
  258 + <a href="#">Venecia</a>
  259 + </div>
  260 + </li>
  261 +
  262 + <li>Комплектация кровли
  263 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  264 + <div class="price_filter">
  265 + <a href="#">RUUKI</a>
  266 + <a href="#">Venecia</a>
  267 + </div>
  268 + </li>
  269 +
  270 + <li>Водосточные системы
  271 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  272 + <div class="price_filter">
  273 + <a href="#">RUUKI</a>
  274 + <a href="#">Venecia</a>
  275 + </div>
  276 + </li>
  277 +
  278 + <li>Чердачные лестницы
  279 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  280 + <div class="price_filter">
  281 + <a href="#">RUUKI</a>
  282 + <a href="#">Venecia</a>
  283 + </div>
  284 + </li>
  285 +
  286 + <li>Мансардные окна
  287 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  288 + <div class="price_filter">
  289 + <a href="#">RUUKI</a>
  290 + <a href="#">Venecia</a>
  291 + </div>
  292 + </li>
  293 +
  294 + <li>Металлочерепица
  295 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  296 + <div class="price_filter">
  297 + <a href="#">RUUKI</a>
  298 + <a href="#">Venecia</a>
  299 + </div>
  300 + </li>
  301 +
  302 + <li>Плоская кровля
  303 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  304 + <div class="price_filter">
  305 + <a href="#">RUUKI</a>
  306 + <a href="#">Venecia</a>
  307 + </div>
  308 + </li>
  309 +
  310 + <li>Профнастил
  311 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  312 + <div class="price_filter">
  313 + <a href="#">RUUKI</a>
  314 + <a href="#">Venecia</a>
  315 + </div>
  316 + </li>
  317 +
  318 + <li>Ондулин
  319 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  320 + <div class="price_filter">
  321 + <a href="#">RUUKI</a>
  322 + <a href="#">Venecia</a>
  323 + </div>
  324 + </li>
  325 +
  326 + <li>OSB плиты
  327 + <div class="arrow"><img src="/images/head_down.png" alt=""></i></div>
  328 + <div class="price_filter">
  329 + <a href="#">RUUKI</a>
  330 + <a href="#">Venecia</a>
  331 + </div>
  332 + </li>
  333 +
  334 + </ul>
  335 + </div>-->
  336 + </div>
  337 +
  338 +
  339 + </div>
  340 +
  341 + <!-- catalog list with all item cards -->
  342 + <div class="cat_p_catalog_list">
  343 + <div class="title"><?= $category->name?> <span>(<?= $product_count?>)</span></div>
  344 +
  345 + <!-- sort menu -->
  346 + <div class="sort_menu">
  347 +
  348 + <div class="sort_price">
  349 + <span>Сортировка:</span>
  350 + <?= \yii\widgets\LinkSorter::widget([
  351 + 'sort' => $sort,
  352 + 'attributes' => [
  353 + 'name',
  354 + 'price',
  355 + ]
  356 + ]);
  357 + ?>
  358 + <!--
  359 + <select name="sort_price" id="" class="sort_price_select">
  360 + <option value="price">по цене</option>
  361 + <option value="popular">новые</option>
  362 + <option value="sale">по акции</option>
  363 + </select>
  364 + <i class="fa fa-angle-down"></i>-->
  365 + </div>
  366 +
  367 + <div class="show">
  368 + <!--<span>Показывать по:</span>
  369 + <ul>
  370 + <li><a class="active" href="#">24</a></li>
  371 + <li><a href="#">48</a></li>
  372 + <li><a href="#">96</a></li>
  373 + </ul>-->
  374 + </div>
  375 +
  376 + <div class="show_pages">
  377 + <?php if ($pages->totalCount > $pages->pageSize) :?>
  378 + <span>Страница:</span>
  379 + <?= \yii\widgets\LinkPager::widget([
  380 + 'pagination' => $pages,
  381 + 'options' => ['class' => 'pagination pull-right'],
  382 + ]);
  383 + ?>
  384 + <!--<i class="fa fa-caret-right"></i>-->
38 <?php endif?> 385 <?php endif?>
39 </div> 386 </div>
40 - <!-- $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'alias' => $parent->alias]];-->  
41 - <?php endforeach?>  
42 387
43 - </div><!-- end of 3 colons for items --> 388 + </div>
  389 +
  390 +
  391 + <div class="cat_p_item_card_list">
  392 + <div class="novelty">
  393 + <div class="content">
  394 + <div class="novelty_cont">
  395 + <?php foreach($products as $product) :?>
  396 + <?php require(__DIR__ .'/product_item.php')?>
  397 + <?php endforeach?>
  398 + </div>
  399 +
  400 + <?php if ($pages->totalCount > $pages->pageSize) :?>
  401 + <!-- LOAD MORE BUTTON -->
  402 + <button class="load_more_btn">Загрузить еще <?= $per_page?> товара</button>
  403 +
  404 + <div class="show_pages">
  405 + Страница:
  406 + <?= \yii\widgets\LinkPager::widget([
  407 + 'pagination' => $pages,
  408 + 'options' => ['class' => 'pagination pull-right'],
  409 + ]);
  410 + ?>
  411 + <!--<i class="fa fa-caret-right"></i>-->
  412 + </div>
  413 + <?php endif?>
  414 + <hr>
  415 +
  416 + <div class="description">
  417 + <h2>Преимущества металлочерепицы:</h2>
  418 + <p>
  419 + На рынке стройматериалов представлено множество кровельных покрытий, от привычного всем рубероида до современной гибкой черепицы на основе стекловолоконных композитов. Все они имеют свои преимущества и сферы применения. Но металлочерепица на протяжении многих лет удерживает лидерские позиции по уровню продаж, и этzо объясняется несколькими причинами:
  420 + </p>
  421 + <h4>Кровля из металлочерепицы</h4>
  422 + <p class="margin_bottom_20">
  423 + <span class="bold">1. Малый вес.</span> Эта характеристика дает ощутимую финансовую выгоду. Вам не придется усиливать стропильные конструкции, значит, удастся сэкономить на пиломатериалах. Легкость металлочерепицы для кровли упрощает транспортировку и монтаж, позволяет отказаться от дорогостоящих услуг подъемной и грузовой спецтехники.
  424 + </p>
  425 + <p class="margin_bottom_20">
  426 + <span class="bold">2. Прочность.</span> В отличие от рулонных и гибких материалов, металлочерепица устойчива к механическим повреждениям. Ее крайне сложно поцарапать и практически невозможно сломать. Высокие технические характеристики говорят и о хорошей несущей способности материала.
  427 + </p>
  428 + <p class="margin_bottom_20">
  429 + <span class="bold">3. Эстетичность.</span> Металлочерепица придает крыше законченный, аккуратный вид. Дом выглядит просто роскошно. Подбирая оригинальные цветовые сочетания, дизайнерам удается с помощью
  430 + </p>
  431 +
  432 + <div class="empty_padding_400"></div>
  433 + </div>
  434 + </div>
  435 + </div>
  436 + </div>
  437 + </div>
  438 +</div>
44 439
45 -</div>  
46 \ No newline at end of file 440 \ No newline at end of file
frontend/views/вертска/js/my_scripts.js
@@ -2,16 +2,6 @@ $(document).ready(function(){ @@ -2,16 +2,6 @@ $(document).ready(function(){
2 // ion tabs 2 // ion tabs
3 $.ionTabs("#tabs_1"); 3 $.ionTabs("#tabs_1");
4 4
5 - // price rangeslider (filter price slider)  
6 - $("#example_id").ionRangeSlider({  
7 - type: "double",  
8 - min: 0,  
9 - max: 500,  
10 - from: 50,  
11 - to: 450,  
12 - grid: false  
13 - });  
14 -  
15 // ion checkradio init 5 // ion checkradio init
16 $("input[type='radio'], input[type='checkbox']").ionCheckRadio(); 6 $("input[type='radio'], input[type='checkbox']").ionCheckRadio();
17 7
frontend/web/css/style.css
@@ -501,6 +501,11 @@ button:focus {outline: none;} @@ -501,6 +501,11 @@ button:focus {outline: none;}
501 padding-bottom:60px; 501 padding-bottom:60px;
502 color:#333333; 502 color:#333333;
503 } 503 }
  504 +.novelty_cont:after {
  505 + display: block;
  506 + content: '';
  507 + clear: both;
  508 +}
504 .novelty_cont .item{ 509 .novelty_cont .item{
505 border:1px solid #cdd1d9; 510 border:1px solid #cdd1d9;
506 border-bottom:none; 511 border-bottom:none;