Commit b519af228167867d15d4e91e1113387838daed3f
1 parent
9d33ce37
Base-product functional
Showing
29 changed files
with
1218 additions
and
133 deletions
Show diff stats
common/components/artboxtree/ArtboxTreeBehavior.php
... | ... | @@ -20,6 +20,7 @@ class ArtboxTreeBehavior extends Behavior { |
20 | 20 | public $keyNameGroup = 'group'; |
21 | 21 | public $keyNamePath = 'path_int'; |
22 | 22 | public $keyNameDepth = 'depth'; // @todo -> $keyNameDepth; |
23 | + public $primaryKeyMode = true; | |
23 | 24 | |
24 | 25 | /** |
25 | 26 | * @var string |
... | ... | @@ -88,8 +89,31 @@ class ArtboxTreeBehavior extends Behavior { |
88 | 89 | * get all-level children items |
89 | 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 | 127 | * Full-path (use MP-method) |
104 | 128 | */ |
105 | 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 | 151 | $path = $this->getParentPath(); |
107 | 152 | if ($path !== null) { |
108 | - $paths = str_replace(['{', '}'], '', explode(',', $path)); | |
153 | + $paths = explode(',', trim($path, '{}')); | |
109 | 154 | if (!$this->primaryKeyMode) { |
110 | 155 | $path = null; |
111 | 156 | $paths = array_map( |
... | ... | @@ -123,7 +168,6 @@ class ArtboxTreeBehavior extends Behavior { |
123 | 168 | } |
124 | 169 | |
125 | 170 | $tableName = $this->owner->tableName(); |
126 | - $condition = ['and']; | |
127 | 171 | if ($this->primaryKeyMode) { |
128 | 172 | $condition[] = ["{$tableName}.[[{$this->keyNameId}]]" => $paths]; |
129 | 173 | } else { |
... | ... | @@ -132,12 +176,12 @@ class ArtboxTreeBehavior extends Behavior { |
132 | 176 | |
133 | 177 | $query = $this->owner->find() |
134 | 178 | ->andWhere($condition) |
135 | - ->andWhere($this->treeCondition()) | |
179 | + ->andWhere($this->groupWhere()) | |
136 | 180 | ->addOrderBy(["{$tableName}.[[{$this->keyNamePath}]]" => SORT_ASC]); |
137 | 181 | $query->multiple = true; |
138 | 182 | |
139 | 183 | return $query; |
140 | - } | |
184 | + }*/ | |
141 | 185 | |
142 | 186 | /** |
143 | 187 | * @param bool $asArray = false |
... | ... | @@ -147,14 +191,26 @@ class ArtboxTreeBehavior extends Behavior { |
147 | 191 | { |
148 | 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 | 208 | public function getAllChildrenMP($depth = null) |
152 | 209 | { |
153 | 210 | $tableName = $this->owner->tableName(); |
154 | 211 | $path = $this->owner->getAttribute($this->keyNamePath); |
155 | 212 | $query = $this->owner->find() |
156 | - ->andWhere(['@>', "{$tableName}.[[{$this->keyNamePath}]]", $this->getLike($path), false]); | |
157 | - | |
213 | + ->andWhere(['@>', "{$tableName}.[[{$this->keyNamePath}]]", $path]); | |
158 | 214 | |
159 | 215 | if ($depth > 0) { |
160 | 216 | $query->andWhere(['<=', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth) + $depth]); |
... | ... | @@ -165,7 +221,7 @@ class ArtboxTreeBehavior extends Behavior { |
165 | 221 | $orderBy["{$tableName}.[[{$this->keyNameId}]]"] = SORT_ASC; |
166 | 222 | |
167 | 223 | $query |
168 | - ->andWhere($this->treeCondition()) | |
224 | + ->andWhere($this->groupWhere()) | |
169 | 225 | ->addOrderBy($orderBy); |
170 | 226 | $query->multiple = true; |
171 | 227 | |
... | ... | @@ -186,7 +242,13 @@ class ArtboxTreeBehavior extends Behavior { |
186 | 242 | $parent_id = $this->owner->getAttribute($this->keyNameParentId); |
187 | 243 | if (empty($parent_id)) |
188 | 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 | 278 | * @return ActiveQuery |
217 | 279 | */ |
218 | 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 | 337 | */ |
272 | 338 | protected static function getParentPathInternal($path, $asArray = false) |
273 | 339 | { |
274 | - $path = str_replace(['{', '}'], '', explode(',', $path)); | |
340 | + $path = explode(',', trim($path, '{}')); | |
275 | 341 | array_pop($path); |
276 | 342 | if ($asArray) { |
277 | 343 | return $path; |
... | ... | @@ -348,7 +414,7 @@ class ArtboxTreeBehavior extends Behavior { |
348 | 414 | // $this->keyNamePath => $path |
349 | 415 | // ]); |
350 | 416 | |
351 | - $this->owner->setAttribute('path_int', $path); | |
417 | + $this->owner->setAttribute($this->keyNamePath, $path); | |
352 | 418 | // $this->owner->setAttribute($this->keyNamePath, $path); |
353 | 419 | $this->owner->setAttribute($this->keyNameDepth, $depth); |
354 | 420 | } | ... | ... |
common/components/artboxtree/ArtboxTreeQueryTrait.php
... | ... | @@ -23,18 +23,17 @@ trait ArtboxTreeQueryTrait { |
23 | 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 | 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 | 33 | if (empty($data)) |
33 | 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 | 39 | private function _recursiveRebuild($tree, $parentPath = null, $depth = 0) { | ... | ... |
common/config/main.php
... | ... | @@ -86,16 +86,13 @@ return [ |
86 | 86 | 'linked_key' => 'product_id', |
87 | 87 | ], |
88 | 88 | 'entity2' => [ |
89 | - 'model' => '\common\modules\rubrication\models\TaxOption', | |
89 | + 'model' => '\common\modules\product\models\Category', | |
90 | 90 | 'label' => 'Category', |
91 | - 'listField' => 'ValueRenderFlash', | |
92 | - 'key' => 'tax_option_id', | |
91 | + 'listField' => 'name', | |
92 | + 'key' => 'category_id', | |
93 | 93 | 'linked_key' => 'category_id', |
94 | - 'where' => [ | |
95 | - 'tax_group_id' => 1 | |
96 | - ], | |
97 | 94 | 'hierarchy' => [ |
98 | - 'key' => 'tax_option_id', | |
95 | + 'key' => 'category_id', | |
99 | 96 | 'parentKey' => 'parent_id', |
100 | 97 | ] |
101 | 98 | ], |
... | ... | @@ -103,6 +100,33 @@ return [ |
103 | 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 | 130 | 'relation_categories' => [ |
107 | 131 | 'name' => Yii::t('relation', 'Relation categories'), |
108 | 132 | 'field' => 'categories', |
... | ... | @@ -194,7 +218,7 @@ return [ |
194 | 218 | 'model' => 'common\modules\rubrication\models\TaxOptionRelation', |
195 | 219 | 'alias' => 'alias', |
196 | 220 | ] |
197 | - ] | |
221 | + ]*/ | |
198 | 222 | ] |
199 | 223 | ], |
200 | 224 | 'comment' => [ | ... | ... |
common/modules/product/controllers/ManageController.php
... | ... | @@ -2,6 +2,9 @@ |
2 | 2 | |
3 | 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 | 8 | use Yii; |
6 | 9 | use common\modules\product\models\Product; |
7 | 10 | use common\modules\product\models\ProductSearch; |
... | ... | @@ -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 | 68 | * Lists all Product models. |
34 | 69 | * @return mixed | ... | ... |
common/modules/product/helpers/ProductHelper.php
... | ... | @@ -2,23 +2,16 @@ |
2 | 2 | |
3 | 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 | 7 | use yii\base\Object; |
7 | 8 | |
8 | 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 | 10 | public static function getCategories() { |
18 | - return TaxOption::find()->getTree(self::getCategoryGroupId()); | |
11 | + return Category::find()->getTree(); | |
19 | 12 | } |
20 | 13 | |
21 | 14 | public static function getBrands() { |
22 | - return TaxOption::find()->where(['tax_group_id' => self::getBrandGroupId()]); | |
15 | + return Brand::find(); | |
23 | 16 | } |
24 | 17 | } |
25 | 18 | \ No newline at end of file | ... | ... |
common/modules/product/models/Category.php
... | ... | @@ -4,6 +4,7 @@ namespace common\modules\product\models; |
4 | 4 | |
5 | 5 | use common\behaviors\Slug; |
6 | 6 | use common\components\artboxtree\ArtboxTreeBehavior; |
7 | +use common\modules\relation\relationBehavior; | |
7 | 8 | use common\modules\rubrication\behaviors\ArtboxSynonymBehavior; |
8 | 9 | use Yii; |
9 | 10 | |
... | ... | @@ -53,6 +54,12 @@ class Category extends \yii\db\ActiveRecord |
53 | 54 | 'valueFields' => [ // postKey => DBFieldName |
54 | 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 | 11 | * This is the model class for table "{{%product}}". |
12 | 12 | * |
13 | 13 | * @property string $name |
14 | - * @property integer $tax_brand_id | |
14 | + * @property integer $brand_id | |
15 | 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 | 22 | class Product extends \yii\db\ActiveRecord |
20 | 23 | { |
24 | + /** @var array $variants */ | |
25 | + public $_variants = []; | |
21 | 26 | /** |
22 | 27 | * @inheritdoc |
23 | 28 | */ |
... | ... | @@ -47,9 +52,9 @@ class Product extends \yii\db\ActiveRecord |
47 | 52 | public function rules() |
48 | 53 | { |
49 | 54 | return [ |
50 | - [['tax_brand_id'], 'integer'], | |
55 | + [['brand_id'], 'integer'], | |
51 | 56 | [['name'], 'string', 'max' => 150], |
52 | - [['categories'], 'safe'], | |
57 | + [['categories', 'variants'], 'safe'], | |
53 | 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 | 65 | public function attributeLabels() |
61 | 66 | { |
62 | 67 | return [ |
63 | - 'product_id' => Yii::t('product', 'Product ID'), | |
68 | + 'product_id' => Yii::t('product', 'ID'), | |
64 | 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 | 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 | 78 | */ |
74 | 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 | 140 | public function getCategory() { |
... | ... | @@ -91,8 +142,8 @@ class Product extends \yii\db\ActiveRecord |
91 | 142 | $categories = $this->getRelations('product_categories'); |
92 | 143 | $count = $categories->count(); |
93 | 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 | 154 | { |
104 | 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 | 26 | return 'product_category'; |
27 | 27 | } |
28 | 28 | |
29 | - | |
30 | 29 | /** |
31 | 30 | * @inheritdoc |
32 | 31 | */ |
33 | 32 | public function rules() |
34 | 33 | { |
35 | 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 | 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 | 45 | { |
47 | 46 | return [ |
48 | 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 | ... | ... |
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 | 31 | { |
32 | 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 | 67 | |
68 | 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 | } | ... | ... |
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 | 5 | use yii\helpers\ArrayHelper; |
6 | 6 | use common\components\artboxtree\ArtboxTreeHelper; |
7 | 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 | 12 | /* @var $this yii\web\View */ |
10 | 13 | /* @var $model common\modules\product\models\Product */ |
... | ... | @@ -17,23 +20,76 @@ use common\modules\product\helpers\ProductHelper; |
17 | 20 | |
18 | 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 | 26 | 'prompt' => Yii::t('product', 'Select brand') |
24 | 27 | ] |
25 | 28 | ) ?> |
26 | - <?php | |
27 | -// var_dump($model->categories); | |
28 | - ?> | |
29 | + | |
29 | 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 | 33 | // 'prompt' => Yii::t('product', 'Select category'), |
33 | 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 | 93 | <div class="form-group"> |
38 | 94 | <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> |
39 | 95 | </div> | ... | ... |
common/modules/product/views/manage/_search.php
common/modules/product/views/manage/index.php
... | ... | @@ -22,11 +22,10 @@ $this->params['breadcrumbs'][] = $this->title; |
22 | 22 | 'filterModel' => $searchModel, |
23 | 23 | 'columns' => [ |
24 | 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 | 30 | ['class' => 'yii\grid\ActionColumn'], |
32 | 31 | ], | ... | ... |
common/modules/product/views/manage/view.php
... | ... | @@ -28,9 +28,11 @@ $this->params['breadcrumbs'][] = $this->title; |
28 | 28 | <?= DetailView::widget([ |
29 | 29 | 'model' => $model, |
30 | 30 | 'attributes' => [ |
31 | - 'name', | |
32 | - 'tax_brand_id', | |
33 | 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 | 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 | 3 | <div class="submenu"> |
4 | 4 | <ul class="categories"> |
5 | 5 | <li class="sub_cat"><span>Популярные категории</span> |
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | <div class="sub_cat_content"> |
8 | 8 | <div class="content_items"> |
9 | 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 | 11 | <div valign="top" class="picture"><img valign="top" src="<?= $_item->image?>"></div> |
12 | 12 | <div class="title"><?= $_item->name?></div> |
13 | 13 | </a></div> |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | <div class="sub_cat_content"> |
24 | 24 | <div class="content_items"> |
25 | 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 | 27 | <div valign="top" class="picture"><img valign="top" src="<?= $_item['item']->image?>"></div> |
28 | 28 | <div class="title"><?= $_item['item']->name?></div> |
29 | 29 | </a></div> | ... | ... |
common/modules/relation/relationQueryTrait.php
... | ... | @@ -21,7 +21,13 @@ trait relationQueryTrait { |
21 | 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 | 34 | \ No newline at end of file | ... | ... |
common/modules/rubrication/Module.php
... | ... | @@ -8,7 +8,7 @@ use Yii; |
8 | 8 | */ |
9 | 9 | class Module extends \yii\base\Module |
10 | 10 | { |
11 | - public $types; | |
11 | + public $types = []; | |
12 | 12 | /** |
13 | 13 | * @inheritdoc |
14 | 14 | */ |
... | ... | @@ -22,7 +22,5 @@ class Module extends \yii\base\Module |
22 | 22 | public function init() |
23 | 23 | { |
24 | 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 | 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 | 58 | public function rules() |
53 | 59 | { |
54 | 60 | return [ |
55 | - [['alias', 'name', 'module'], 'required'], | |
61 | + [['name', 'module'], 'required'], | |
56 | 62 | [['description', 'settings'], 'string'], |
57 | 63 | [['hierarchical'], 'boolean'], |
58 | 64 | [['alias', 'module'], 'string', 'max' => 50], | ... | ... |
common/modules/rubrication/models/TaxOption.php
... | ... | @@ -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 | 57 | * @inheritdoc |
65 | 58 | */ |
... | ... | @@ -226,6 +219,7 @@ class TaxOption extends \yii\db\ActiveRecord |
226 | 219 | |
227 | 220 | private function getValueModelName() { |
228 | 221 | $group = $this->getTaxGroup()->one(); |
222 | +// var_dump($group);exit; | |
229 | 223 | $valueClass = '\common\modules\rubrication\models\TaxValue'. ucfirst($group->module); |
230 | 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 | 2 | |
3 | 3 | namespace frontend\controllers; |
4 | 4 | |
5 | +use common\modules\product\models\Brand; | |
5 | 6 | use common\modules\product\models\Category; |
6 | 7 | use common\modules\product\models\CategorySearch; |
7 | 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 | 16 | use yii\web\HttpException; |
9 | 17 | |
10 | 18 | class CatalogController extends \yii\web\Controller |
... | ... | @@ -12,6 +20,9 @@ class CatalogController extends \yii\web\Controller |
12 | 20 | public function actionCategory($alias) |
13 | 21 | { |
14 | 22 | $category = CategorySearch::findByAlias($alias); |
23 | + if (empty($category->category_id)) { | |
24 | + throw new HttpException(404 ,'Page not found'); | |
25 | + } | |
15 | 26 | if ($category->depth < 2) { |
16 | 27 | return $this->render( |
17 | 28 | 'categories', |
... | ... | @@ -20,11 +31,62 @@ class CatalogController extends \yii\web\Controller |
20 | 31 | ] |
21 | 32 | ); |
22 | 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 | 77 | return $this->render( |
25 | 78 | 'products', |
26 | 79 | [ |
27 | 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 | 94 | |
33 | 95 | public function actionProduct($alias) |
34 | 96 | { |
35 | - $product = Product::find()->where('like', ['alias' => $alias]); | |
97 | + $product = ProductSearch::findByAlias($alias); | |
36 | 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 | 101 | return $this->render('product'); |
41 | 102 | } | ... | ... |
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 | 16 | \ No newline at end of file | ... | ... |
frontend/views/catalog/products.php
... | ... | @@ -6,40 +6,434 @@ $this->title = $category->name; |
6 | 6 | foreach($category->getParents()->all() as $parent) { |
7 | 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 | 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 | 385 | <?php endif?> |
39 | 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 | 440 | \ No newline at end of file | ... | ... |
frontend/views/вертска/js/my_scripts.js
... | ... | @@ -2,16 +2,6 @@ $(document).ready(function(){ |
2 | 2 | // ion tabs |
3 | 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 | 5 | // ion checkradio init |
16 | 6 | $("input[type='radio'], input[type='checkbox']").ionCheckRadio(); |
17 | 7 | ... | ... |
frontend/web/css/style.css
... | ... | @@ -501,6 +501,11 @@ button:focus {outline: none;} |
501 | 501 | padding-bottom:60px; |
502 | 502 | color:#333333; |
503 | 503 | } |
504 | +.novelty_cont:after { | |
505 | + display: block; | |
506 | + content: ''; | |
507 | + clear: both; | |
508 | +} | |
504 | 509 | .novelty_cont .item{ |
505 | 510 | border:1px solid #cdd1d9; |
506 | 511 | border-bottom:none; | ... | ... |