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,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 |
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 | } |
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->params['breadcrumbs'][] = $this->title; | @@ -22,11 +22,10 @@ $this->params['breadcrumbs'][] = $this->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->params['breadcrumbs'][] = $this->title; | @@ -28,9 +28,11 @@ $this->params['breadcrumbs'][] = $this->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 | } |
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->title = $category->name; | @@ -6,40 +6,434 @@ $this->title = $category->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; |