Commit 5aa7418e91ad61ac033b90ef0263d30c2aec5160
1 parent
b15c889e
Base-product#3 functional
Showing
17 changed files
with
463 additions
and
22 deletions
Show diff stats
common/config/main.php
... | ... | @@ -100,6 +100,27 @@ return [ |
100 | 100 | 'model' => '\common\modules\product\models\ProductCategory', |
101 | 101 | ] |
102 | 102 | ], |
103 | + 'product_option' => [ | |
104 | + 'name' => Yii::t('product', 'Properties'), | |
105 | + 'field' => 'options', | |
106 | + 'entity1' => [ | |
107 | + 'model' => '\common\modules\product\models\Product', | |
108 | + 'label' => 'Product', | |
109 | + 'listField' => 'fullname', | |
110 | + 'key' => 'product_id', | |
111 | + 'linked_key' => 'product_id', | |
112 | + ], | |
113 | + 'entity2' => [ | |
114 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
115 | + 'label' => 'Option', | |
116 | + 'listField' => 'ValueeRenderFlash', | |
117 | + 'key' => 'tax_option_id', | |
118 | + 'linked_key' => 'option_id', | |
119 | + ], | |
120 | + 'via' => [ | |
121 | + 'model' => 'common\modules\product\models\ProductOption', | |
122 | + ] | |
123 | + ], | |
103 | 124 | 'tax_group_to_category' => [ |
104 | 125 | 'name' => Yii::t('product', 'Характеристики по категориям'), |
105 | 126 | 'field' => 'group_to_category', | ... | ... |
common/modules/product/controllers/ManageController.php
... | ... | @@ -33,6 +33,24 @@ class ManageController extends Controller |
33 | 33 | } |
34 | 34 | |
35 | 35 | public function actionTest() { |
36 | + return; | |
37 | + foreach(Product::find()->all() as $product) { | |
38 | + if (!$product->variant) { | |
39 | + $product->save(); | |
40 | + $variantModel = new ProductVariant(); | |
41 | + $variantModel->product_id = $product->product_id; | |
42 | + $variantModel->name = 'test-'. uniqid(); | |
43 | + $variantModel->sku = $variantModel->name; | |
44 | + $variantModel->price = rand(5, 200000); | |
45 | + $variantModel->price_old = rand(0, 5) > 3 ? $variantModel->price* (1+rand(0, 10) / 10) : $variantModel->price; | |
46 | + $variantModel->product_unit_id = rand(1, 5); | |
47 | + $variantModel->stock = rand(0, 50); | |
48 | + $variantModel->save(); | |
49 | + } | |
50 | + } | |
51 | + | |
52 | + return; | |
53 | + | |
36 | 54 | $categories = Category::find()->where(['depth' => 2])->all(); |
37 | 55 | $cats_ids = []; |
38 | 56 | foreach($categories as $cat) { |
... | ... | @@ -122,8 +140,11 @@ class ManageController extends Controller |
122 | 140 | if ($model->load(Yii::$app->request->post()) && $model->save()) { |
123 | 141 | return $this->redirect(['view', 'id' => $model->product_id]); |
124 | 142 | } else { |
143 | + $groups = $model->category->getTaxGroups(); | |
144 | + | |
125 | 145 | return $this->render('update', [ |
126 | 146 | 'model' => $model, |
147 | + 'groups' => $groups, | |
127 | 148 | ]); |
128 | 149 | } |
129 | 150 | } | ... | ... |
common/modules/product/models/Product.php
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | |
3 | 3 | namespace common\modules\product\models; |
4 | 4 | |
5 | +use common\behaviors\Slug; | |
5 | 6 | use common\modules\rubrication\models\TaxOption; |
6 | 7 | use Yii; |
7 | 8 | use common\modules\relation\relationBehavior; |
... | ... | @@ -23,6 +24,9 @@ class Product extends \yii\db\ActiveRecord |
23 | 24 | { |
24 | 25 | /** @var array $variants */ |
25 | 26 | public $_variants = []; |
27 | + | |
28 | + /** @var array $_images */ | |
29 | + public $imagesUpload = []; | |
26 | 30 | /** |
27 | 31 | * @inheritdoc |
28 | 32 | */ |
... | ... | @@ -32,9 +36,16 @@ class Product extends \yii\db\ActiveRecord |
32 | 36 | [ |
33 | 37 | 'class' => relationBehavior::className(), |
34 | 38 | 'relations' => [ |
35 | - 'product_categories' => 'entity1' // Product category | |
39 | + 'product_categories' => 'entity1', // Product category | |
40 | + 'product_option' => 'entity1' // Product category | |
36 | 41 | ] |
37 | 42 | ], |
43 | + [ | |
44 | + 'class' => Slug::className(), | |
45 | + 'in_attribute' => 'name', | |
46 | + 'out_attribute' => 'alias', | |
47 | + 'translit' => true | |
48 | + ] | |
38 | 49 | ]; |
39 | 50 | } |
40 | 51 | |
... | ... | @@ -54,7 +65,10 @@ class Product extends \yii\db\ActiveRecord |
54 | 65 | return [ |
55 | 66 | [['brand_id'], 'integer'], |
56 | 67 | [['name'], 'string', 'max' => 150], |
57 | - [['categories', 'variants'], 'safe'], | |
68 | + [['alias'], 'string', 'max' => 250], | |
69 | + [['categories', 'variants', 'options'], 'safe'], | |
70 | + [['imagesUpload'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif'], | |
71 | + [['description', 'video'], 'safe'], | |
58 | 72 | // [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']], |
59 | 73 | ]; |
60 | 74 | } |
... | ... | @@ -70,6 +84,8 @@ class Product extends \yii\db\ActiveRecord |
70 | 84 | 'brand_id' => Yii::t('product', 'Brand'), |
71 | 85 | 'categories' => Yii::t('product', 'Categories'), // relation behavior field |
72 | 86 | 'category' => Yii::t('product', 'Category'), // relation behavior field |
87 | + 'image' => Yii::t('product', 'Image'), | |
88 | + 'images' => Yii::t('product', 'Images'), | |
73 | 89 | ]; |
74 | 90 | } |
75 | 91 | |
... | ... | @@ -97,6 +113,10 @@ class Product extends \yii\db\ActiveRecord |
97 | 113 | return $this->hasMany(ProductImage::className(), ['product_id' => 'product_id']); |
98 | 114 | } |
99 | 115 | |
116 | + public function setImages($images) { | |
117 | + $this->_images = $images; | |
118 | + } | |
119 | + | |
100 | 120 | /** |
101 | 121 | * @return \yii\db\ActiveQuery |
102 | 122 | */ |
... | ... | @@ -146,6 +166,10 @@ class Product extends \yii\db\ActiveRecord |
146 | 166 | return $categories->one(); |
147 | 167 | } |
148 | 168 | |
169 | + public function getOptions() { | |
170 | + return $this->getRelations('product_option'); | |
171 | + } | |
172 | + | |
149 | 173 | /** |
150 | 174 | * @inheritdoc |
151 | 175 | * @return ProductQuery the active query used by this AR class. |
... | ... | @@ -159,11 +183,18 @@ class Product extends \yii\db\ActiveRecord |
159 | 183 | { |
160 | 184 | parent::afterSave($insert, $changedAttributes); |
161 | 185 | |
186 | + foreach($this->imagesUpload as $image) { | |
187 | + $image->saveAs('/images/items/' . $image->baseName .'_'. uniqid() . '.' . $image->extension); | |
188 | + } | |
189 | + | |
162 | 190 | $todel = []; |
163 | 191 | foreach ($this->variants ? : [] as $_variant) { |
164 | 192 | $todel[$_variant->product_variant_id] = $_variant->product_variant_id; |
165 | 193 | } |
166 | 194 | foreach ($this->_variants as $_variant) { |
195 | + if (!is_array($_variant)) { | |
196 | + return; | |
197 | + } | |
167 | 198 | if (!empty($_variant['product_variant_id'])) { |
168 | 199 | unset($todel[$_variant['product_variant_id']]); |
169 | 200 | $model = ProductVariant::findOne($_variant['product_variant_id']); | ... | ... |
1 | +<?php | |
2 | + | |
3 | +namespace common\modules\product\models; | |
4 | + | |
5 | +use Yii; | |
6 | + | |
7 | +/** | |
8 | + * This is the model class for table "product_option". | |
9 | + * | |
10 | + * @property integer $product_id | |
11 | + * @property integer $option_id | |
12 | + * | |
13 | + * @property Product $product | |
14 | + * @property TaxOption $option | |
15 | + */ | |
16 | +class ProductOption extends \yii\db\ActiveRecord | |
17 | +{ | |
18 | + /** | |
19 | + * @inheritdoc | |
20 | + */ | |
21 | + public static function tableName() | |
22 | + { | |
23 | + return 'product_option'; | |
24 | + } | |
25 | + | |
26 | + /** | |
27 | + * @inheritdoc | |
28 | + */ | |
29 | + public function rules() | |
30 | + { | |
31 | + return [ | |
32 | + [['product_id', 'option_id'], 'required'], | |
33 | + [['product_id', 'option_id'], 'integer'], | |
34 | + [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']], | |
35 | + [['option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['option_id' => 'tax_option_id']], | |
36 | + ]; | |
37 | + } | |
38 | + | |
39 | + /** | |
40 | + * @inheritdoc | |
41 | + */ | |
42 | + public function attributeLabels() | |
43 | + { | |
44 | + return [ | |
45 | + 'product_id' => Yii::t('product', 'Product ID'), | |
46 | + 'option_id' => Yii::t('product', 'Option ID'), | |
47 | + ]; | |
48 | + } | |
49 | + | |
50 | + /** | |
51 | + * @return \yii\db\ActiveQuery | |
52 | + */ | |
53 | + public function getProduct() | |
54 | + { | |
55 | + return $this->hasOne(Product::className(), ['product_id' => 'product_id']); | |
56 | + } | |
57 | + | |
58 | + /** | |
59 | + * @return \yii\db\ActiveQuery | |
60 | + */ | |
61 | + public function getOption() | |
62 | + { | |
63 | + return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'option_id']); | |
64 | + } | |
65 | +} | ... | ... |
common/modules/product/models/ProductSearch.php
... | ... | @@ -6,6 +6,7 @@ use Yii; |
6 | 6 | use yii\base\Model; |
7 | 7 | use yii\data\ActiveDataProvider; |
8 | 8 | use common\modules\product\models\Product; |
9 | +use yii\web\NotFoundHttpException; | |
9 | 10 | |
10 | 11 | /** |
11 | 12 | * ProductSearch represents the model behind the search form about `common\modules\product\models\Product`. |
... | ... | @@ -70,7 +71,7 @@ class ProductSearch extends Product |
70 | 71 | |
71 | 72 | public static function findByAlias($alias) { |
72 | 73 | /** @var ProductQuery $query */ |
73 | - $query = Category::find(); | |
74 | + $query = Product::find(); | |
74 | 75 | $query->byAlias($alias); |
75 | 76 | if (($model = $query->one()) !== null) { |
76 | 77 | return $model; | ... | ... |
common/modules/product/views/manage/_form.php
... | ... | @@ -20,6 +20,9 @@ use unclead\widgets\MultipleInputColumn; |
20 | 20 | |
21 | 21 | <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?> |
22 | 22 | |
23 | + <?= $form->field($model, 'description')->widget(\mihaildev\ckeditor\CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | |
24 | + <?= $form->field($model, 'video')->textarea()->label('Video embeded'); ?> | |
25 | + | |
23 | 26 | <?= $form->field($model, 'brand_id')->dropDownList( |
24 | 27 | ArrayHelper::map(ProductHelper::getBrands()->all(), 'brand_id', 'name'), |
25 | 28 | [ |
... | ... | @@ -30,21 +33,18 @@ use unclead\widgets\MultipleInputColumn; |
30 | 33 | <?= $form->field($model, 'categories')->dropDownList( |
31 | 34 | ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'category_id', 'name'), |
32 | 35 | [ |
33 | -// 'prompt' => Yii::t('product', 'Select category'), | |
34 | 36 | 'multiple' => true |
35 | 37 | ] |
36 | 38 | ) ?> |
37 | 39 | |
38 | - <?php /*= $form->field($model, 'images[]')->widget(FileInput::classname(), [ | |
40 | + | |
41 | + | |
42 | + <?php /*= $form->field($model, 'imagesUpload[]')->widget(FileInput::classname(), [ | |
39 | 43 | 'options' => [ |
40 | 44 | 'accept' => 'image/*', |
41 | 45 | 'multiple' => true, |
42 | 46 | ], |
43 | - 'pluginOptions' => [ | |
44 | -// 'uploadUrl' => \yii\helpers\Url::to(['/site/file-upload']), | |
45 | - ] | |
46 | - ]); | |
47 | - */?> | |
47 | + ]);*/?> | |
48 | 48 | |
49 | 49 | <?= $form->field($model, 'variants')->widget(MultipleInput::className(), [ |
50 | 50 | 'columns' => [ |
... | ... | @@ -90,6 +90,16 @@ use unclead\widgets\MultipleInputColumn; |
90 | 90 | ]); |
91 | 91 | ?> |
92 | 92 | |
93 | + <?php foreach($groups->all() as $group) :?> | |
94 | + <?= $form->field($model, 'options')->checkboxList( | |
95 | + ArrayHelper::map($group->options, 'tax_option_id', 'ValueRenderFlash'), | |
96 | + [ | |
97 | + 'multiple' => true, | |
98 | + 'unselect' => null, | |
99 | + ] | |
100 | + )->label($group->name);?> | |
101 | + <?php endforeach?> | |
102 | + | |
93 | 103 | <div class="form-group"> |
94 | 104 | <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> |
95 | 105 | </div> | ... | ... |
common/modules/product/views/manage/update.php
common/modules/rubrication/helpers/RubricationHelper.php
... | ... | @@ -40,4 +40,12 @@ class RubricationHelper { |
40 | 40 | return $module->types; |
41 | 41 | |
42 | 42 | } |
43 | + | |
44 | + public function checkboxList($items, $options = []) | |
45 | + { | |
46 | + $this->adjustLabelFor($options); | |
47 | + $this->parts['{input}'] = Html::activeCheckboxList($this->model, $this->attribute, $items, $options); | |
48 | + | |
49 | + return $this; | |
50 | + } | |
43 | 51 | } |
44 | 52 | \ No newline at end of file | ... | ... |
common/modules/rubrication/models/TaxGroup.php
console/migrations/m160304_065108_product.php
... | ... | @@ -69,7 +69,10 @@ class m160304_065108_product extends Migration |
69 | 69 | $this->createTable('{{%product}}', [ |
70 | 70 | 'product_id' => $this->primaryKey(), |
71 | 71 | 'name' => $this->string(255)->notNull(), |
72 | + 'alias' => $this->string(255), | |
72 | 73 | 'brand_id' => $this->integer(), |
74 | + 'description' => $this->text(), | |
75 | + 'video' => $this->text(), | |
73 | 76 | ], $tableOptions); |
74 | 77 | |
75 | 78 | $this->addForeignKey('fki_product_id', 'product_category', 'product_id', 'product', 'product_id', 'NO ACTION', 'NO ACTION'); | ... | ... |
console/migrations/m160324_075409_product_option.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +use yii\db\Migration; | |
4 | + | |
5 | +class m160324_075409_product_option 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_option}}', [ | |
21 | + 'product_id' => $this->integer()->notNull(), | |
22 | + 'option_id' => $this->integer()->notNull(), | |
23 | + ], $tableOptions); | |
24 | + $this->addPrimaryKey('product_option_pkey', 'product_option', ['product_id', 'option_id']); | |
25 | + $this->addForeignKey('product_option_product_fkey', 'product_option', 'product_id', 'product', 'product_id', 'NO ACTION', 'NO ACTION'); | |
26 | + $this->addForeignKey('product_option_option_fkey', 'product_option', 'option_id', 'tax_option', 'tax_option_id', 'NO ACTION', 'NO ACTION'); | |
27 | + } | |
28 | + | |
29 | + public function down() | |
30 | + { | |
31 | + $this->dropTable('{{%product_option}}'); | |
32 | + } | |
33 | + | |
34 | + /* | |
35 | + // Use safeUp/safeDown to run migration code within a transaction | |
36 | + public function safeUp() | |
37 | + { | |
38 | + } | |
39 | + | |
40 | + public function safeDown() | |
41 | + { | |
42 | + } | |
43 | + */ | |
44 | +} | ... | ... |
frontend/controllers/CatalogController.php
... | ... | @@ -7,8 +7,11 @@ use common\modules\product\models\Category; |
7 | 7 | use common\modules\product\models\CategorySearch; |
8 | 8 | use common\modules\product\models\Product; |
9 | 9 | use common\modules\product\models\ProductCategory; |
10 | +use common\modules\product\models\ProductOption; | |
10 | 11 | use common\modules\product\models\ProductSearch; |
11 | 12 | use common\modules\product\models\ProductVariant; |
13 | +use common\modules\rubrication\models\TaxGroup; | |
14 | +use common\modules\rubrication\models\TaxOption; | |
12 | 15 | use yii\data\ActiveDataProvider; |
13 | 16 | use yii\data\Pagination; |
14 | 17 | use yii\data\Sort; |
... | ... | @@ -56,10 +59,34 @@ class CatalogController extends \yii\web\Controller |
56 | 59 | ]); |
57 | 60 | $all_count = $query->count(); |
58 | 61 | |
62 | + $brandsQuery = Brand::find() | |
63 | + ->innerJoinWith('products') | |
64 | + ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. Product::tableName() .'.product_id') | |
65 | + ->where([ | |
66 | + ProductCategory::tableName() .'.category_id' => $category->category_id | |
67 | + ]) | |
68 | + ->groupBy(Brand::tableName() .'.brand_id'); | |
69 | + $brands = $brandsQuery->all(); | |
70 | + $brands_count = $brandsQuery->count(); | |
71 | + | |
72 | + $optionsQuery = TaxOption::find() | |
73 | +// ->select([TaxOption::tableName() .'.tax_option_id', TaxOption::tableName() .'.alias']) | |
74 | + ->innerJoin(ProductOption::tableName(), ProductOption::tableName() .'.option_id='. TaxOption::tableName() .'.tax_option_id') | |
75 | + ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. ProductOption::tableName() .'.product_id') | |
76 | + ->where([ | |
77 | + ProductCategory::tableName() .'.category_id' => $category->category_id | |
78 | + ]) | |
79 | + ->groupBy(TaxOption::tableName() .'.tax_option_id'); | |
80 | + $all_options = []; | |
81 | + foreach($optionsQuery->all() as $_option) { | |
82 | + $all_options[] = $_option; | |
83 | + } | |
84 | + | |
59 | 85 | $priceQuery = clone $query; |
60 | 86 | $priceMin = $priceMinCurr = $priceQuery->min(ProductVariant::tableName() .'.price'); |
61 | 87 | $priceMax = $priceMaxCurr = $priceQuery->max(ProductVariant::tableName() .'.price'); |
62 | 88 | |
89 | + // Prices | |
63 | 90 | if (($price_interval = \Yii::$app->request->get('price_interval')) != false) { |
64 | 91 | $price_interval = explode(';', $price_interval); |
65 | 92 | $price_interval = [ |
... | ... | @@ -75,21 +102,40 @@ class CatalogController extends \yii\web\Controller |
75 | 102 | $priceMaxCurr = $price_interval[1]; |
76 | 103 | } |
77 | 104 | } |
105 | + | |
106 | + $groups = []; | |
107 | + foreach($category->getTaxGroups()->all() as $_group) { | |
108 | + $groups[$_group->tax_group_id] = $_group; | |
109 | + } | |
110 | + foreach ($all_options as $option) { | |
111 | + $groups[$option->tax_group_id]->_options[] = $option; | |
112 | + } | |
113 | + foreach($groups as $i => $group) { | |
114 | + if (empty($group->_options)) | |
115 | + unset($groups[$i]); | |
116 | + } | |
117 | + | |
118 | + // Options | |
119 | + if (($options = \Yii::$app->request->get('option')) != false) { | |
120 | + $query->innerJoin(ProductOption::tableName(), ProductOption::tableName() .'.product_id='. Product::tableName() .'.product_id'); | |
121 | + $query->innerJoin(TaxOption::tableName(), TaxOption::tableName() .'.tax_option_id='. ProductOption::tableName() .'.option_id'); | |
122 | + foreach($options as $group_alias => $option_alias) { | |
123 | + $group = TaxGroup::find()->where(['like', 'alias', $group_alias])->one(); | |
124 | + if (!$group) { | |
125 | + continue; | |
126 | + } | |
127 | + $query->andWhere([TaxOption::tableName() .'.tax_group_id' => $group->tax_group_id, TaxOption::tableName() .'.alias' => $option_alias]); | |
128 | + } | |
129 | + } | |
130 | + | |
78 | 131 | $count = $query->count(); |
132 | + | |
79 | 133 | $pages = new Pagination(['totalCount' => $count, 'pageSize' => $per_page]); |
80 | 134 | $query->offset($pages->offset) |
81 | 135 | ->orderBy($sort->orders) |
82 | 136 | ->limit($pages->limit); |
83 | 137 | $products = $query->all(); |
84 | 138 | |
85 | - $brandsQuery = Brand::find()->innerJoinWith('products')->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. Product::tableName() .'.product_id')->where([ | |
86 | - ProductCategory::tableName() .'.category_id' => $category->category_id | |
87 | - ])->groupBy(Brand::tableName() .'.brand_id'); | |
88 | - $brands = $brandsQuery->all(); | |
89 | - $brands_count = $brandsQuery->count(); | |
90 | - | |
91 | - $groups = $category->getTaxGroups()->all(); | |
92 | - | |
93 | 139 | return $this->render( |
94 | 140 | 'products', |
95 | 141 | [ |
... | ... | @@ -107,6 +153,7 @@ class CatalogController extends \yii\web\Controller |
107 | 153 | 'brands' => $brands, |
108 | 154 | 'brands_count' => $brands_count, |
109 | 155 | 'groups' => $groups, |
156 | + 'options' => $options, | |
110 | 157 | ] |
111 | 158 | ); |
112 | 159 | } |
... | ... | @@ -118,7 +165,22 @@ class CatalogController extends \yii\web\Controller |
118 | 165 | if (empty($product->product_id)) { |
119 | 166 | throw new HttpException(404 ,'Page not found'); |
120 | 167 | } |
121 | - return $this->render('product'); | |
168 | + $groups = []; | |
169 | + foreach($product->category->getTaxGroups()->all() as $_group) { | |
170 | + $groups[$_group->tax_group_id] = $_group; | |
171 | + } | |
172 | + foreach ($product->options as $option) { | |
173 | + $groups[$option->tax_group_id]->_options[] = $option; | |
174 | + } | |
175 | + foreach($groups as $i => $group) { | |
176 | + if (empty($group->_options)) | |
177 | + unset($groups[$i]); | |
178 | + } | |
179 | + | |
180 | + return $this->render('product', [ | |
181 | + 'product' => $product, | |
182 | + 'properties' => $groups, | |
183 | + ]); | |
122 | 184 | } |
123 | 185 | |
124 | 186 | public function actionBrands() | ... | ... |
1 | +<?php | |
2 | +/** @var $this \yii\web\View */ | |
3 | +/** @var $dataProvider \yii\data\ActiveDataProvider */ | |
4 | + | |
5 | +$this->title = $product->name; | |
6 | +foreach($product->category->getParents()->all() as $parent) { | |
7 | + $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'alias' => $parent->alias]]; | |
8 | +} | |
9 | +$this->params['breadcrumbs'][] = ['label' => $product->category->name, 'url' => ['catalog/category', 'alias' => $product->category->alias]]; | |
10 | +$this->params['breadcrumbs'][] = $product->name .' #'. $product->variant->sku; | |
11 | +?> | |
12 | +<h1 class="open_card_item_title"><?= $product->name .' '. $product->variant->name?></h1> | |
13 | + | |
14 | +<div class="item_3_blocks_wrap"> <!-- flex container --> | |
15 | + <div class="item_img_block"> <!-- блок с фотографиями --> | |
16 | + <div class="main_img"> | |
17 | + <?php if (empty($product->image)) :?> | |
18 | + <img src="/images/no_photo_big.png" alt="<?= $product->name?>"> | |
19 | + <?php else :?> | |
20 | + <img src="/images/<?= $product->image->image?>" alt="<?= $product->image->alt ? $product->image->alt : $product->name?>"> | |
21 | + <?php endif?> | |
22 | + <!--<span class="new">НОВИНКА</span> | |
23 | + <span class="top">ТОП</span>--> | |
24 | + </div> | |
25 | + <?php if (!empty($product->images)) :?> | |
26 | + <div class="main_img_slide"> | |
27 | + <?php foreach($product->images as $image) :?> | |
28 | + <div class="small_img_block active"> | |
29 | + <img src="/images/<?= $image->image?>" alt="<?= $image->alt ? $image->alt : $product->name?>"> | |
30 | + </div> | |
31 | + <?php endforeach?> | |
32 | + | |
33 | + <img class="slider_arrow_right" src="/images/slider_right.png" alt=""> | |
34 | + <img class="slider_arrow_left" src="/images/slider_left.png" alt=""> | |
35 | + </div> | |
36 | + <?php endif?> | |
37 | + | |
38 | + </div> <!-- конец блока с фотографиями --> | |
39 | + | |
40 | + | |
41 | + <div class="busket_block"> <!-- блок с счетчиком и кнопкой добавить в корзину --> | |
42 | + <div class="top_code"> | |
43 | + <span class="code">Код: <?= $product->variant->sku?></span> | |
44 | + <span class="have"><img src="/images/ok_icon_green.png" alt=""><?= $product->stock !== 0 ? ' есть в наличии' : ' нет в наличии'?></span> | |
45 | + </div> | |
46 | + | |
47 | + <div class="grey_bg"> | |
48 | + <div class="counter"> | |
49 | + <div class="price"><?= $product->variant->price?></div> | |
50 | + <div class="sign">грн.</div> | |
51 | + <div class="count_block"> | |
52 | + <div class="count_number">1</div> | |
53 | + <div class="count_buttons"> | |
54 | + <div class="button_plus">+</div> | |
55 | + <div class="button_minus">-</div> | |
56 | + </div> | |
57 | + </div> | |
58 | + </div> | |
59 | + | |
60 | + <div class="in_cart_btn"> | |
61 | + <a href="#"> | |
62 | + <button class="cart_btn" data-id="<?= $product->variant->product_variant_id?>"> в корзину <img src="/images/ico_basket_white.png" alt=""></button> | |
63 | + </a> | |
64 | + </div> | |
65 | + | |
66 | + <!--<div class="to_compare_link"> | |
67 | + <img src="/images/ico_scales.png" alt=""> | |
68 | + <a href="#" class="add_to_compare">добавить к сравнению</a> | |
69 | + </div>--> | |
70 | + </div> | |
71 | + <div class="quick_order"> | |
72 | + <form action=""> | |
73 | + <span class="text">БЫСТРЫЙ ЗАКАЗ</span> | |
74 | + <input type="text" class="quick_order_phone" name="quick_order_phone" placeholder="(0XX) XXX-XX-XX"> | |
75 | + <button type="submit">заказать</button> | |
76 | + </form> | |
77 | + </div> | |
78 | + | |
79 | + <div class="delivery"> | |
80 | + <p> | |
81 | + Доставка товара на следующий день после выставления счета. Мы доставим “День в <br> день” — уточните это у менеджера. | |
82 | + </p> | |
83 | + <a href="#">Подробно о доставке</a> | |
84 | + </div> | |
85 | + | |
86 | + </div><!-- конец блока с счетчиком и кнопкой добавить в корзину --> | |
87 | + | |
88 | + <div class="character_block"> <!-- блок с характеристиками --> | |
89 | + <?php if (!empty($properties)) :?> | |
90 | + <h3>Характеристики</h3> | |
91 | + <ul> | |
92 | + <?php foreach($properties as $group) :?> | |
93 | + <li> | |
94 | + <div class="each"> | |
95 | + <div class="title"><?= $group->name?></div> | |
96 | + <div class="tech"> | |
97 | + <?php foreach($group->_options as $option) :?> <?= $option->ValueRenderHTML?><?php endforeach?> | |
98 | + </div> | |
99 | + </div> | |
100 | + </li> | |
101 | + <?php endforeach?> | |
102 | + </ul> | |
103 | + <?php endif?> | |
104 | + | |
105 | + <!--<div class="tech_links"> | |
106 | + <a href="#">Описание</a> | |
107 | + <a href="#">Видео</a> | |
108 | + <a href="#">Отзывы(12)</a> | |
109 | + </div>--> | |
110 | + | |
111 | + </div><!-- закрытие блока с характеристиками --> | |
112 | + | |
113 | + <div class="tabs_block"> <!-- Табы с описанием видео и отзывами --> | |
114 | + <div class="ionTabs" id="tabs_1" data-name="Tabs_Group_name"> | |
115 | + <ul class="ionTabs__head"> | |
116 | + <?php if (!empty($properties)) :?> | |
117 | + <li class="ionTabs__tab" data-target="Tab_1_name">Характеристики</li> | |
118 | + <?php endif?> | |
119 | + <?php if (!empty($product->description)) :?> | |
120 | + <li class="ionTabs__tab" data-target="Tab_2_name">Описание</li> | |
121 | + <?php endif?> | |
122 | + <?php if (!empty($product->description)) :?> | |
123 | + <li class="ionTabs__tab" data-target="Tab_3_name">Видео</li> | |
124 | + <?php endif?> | |
125 | +<!-- <li class="ionTabs__tab" data-target="Tab_4_name">Отзывы(12)</li>--> | |
126 | + </ul> | |
127 | + <div class="ionTabs__body"> | |
128 | + <?php if (!empty($properties)) :?> | |
129 | + <div class="ionTabs__item" data-name="Tab_1_name"> | |
130 | + <ul> | |
131 | + <?php foreach($properties as $group) :?> | |
132 | + <li> | |
133 | + <div class="each"> | |
134 | + <div class="title"><?= $group->name?></div> | |
135 | + <div class="tech"> | |
136 | + <?php foreach($group->_options as $option) :?> <?= $option->ValueRenderHTML?><?php endforeach?> | |
137 | + </div> | |
138 | + </div> | |
139 | + </li> | |
140 | + <?php endforeach?> | |
141 | + </ul> | |
142 | + </div> | |
143 | + <?php endif?> | |
144 | + <?php if (!empty($product->description)) :?> | |
145 | + <div class="ionTabs__item" data-name="Tab_2_name"> | |
146 | + <?= $product->description?> | |
147 | + </div> | |
148 | + <?php endif?> | |
149 | + <?php if (!empty($product->video)) :?> | |
150 | + <div class="ionTabs__item" data-name="Tab_3_name"> | |
151 | + <?= $product->video?> | |
152 | + </div> | |
153 | + <?php endif?> | |
154 | + <!--<div class="ionTabs__item" data-name="Tab_4_name"> | |
155 | + <span class="tabs_item_name">Отзывы</span> | |
156 | + </div>--> | |
157 | + | |
158 | + <div class="ionTabs__preloader"></div> | |
159 | + </div> | |
160 | + </div> | |
161 | + | |
162 | + </div> <!-- конец табов с описанием видео и отзывами --> | |
163 | + | |
164 | +</div> <!-- end flex container --> | ... | ... |
frontend/views/catalog/product_item.php
... | ... | @@ -4,12 +4,21 @@ |
4 | 4 | <div class="item" data-id="<?= $product->product_id?>"> |
5 | 5 | <!--<div class="new">АКЦИЯ</div> |
6 | 6 | <div class="top">Toп</div>--> |
7 | - <a href="#" class="item_link"><div class="pic"><img src="/images/items/01.jpg"></div> | |
7 | + <a href="<?= \yii\helpers\Url::to(['catalog/product', 'alias' => $product->alias])?>" class="item_link"> | |
8 | + <div class="pic"> | |
9 | + <?php if (empty($product->image)) :?> | |
10 | + <img src="/images/no_photo.png"> | |
11 | + <?php else :?> | |
12 | + <img src="/images/<?= $product->image->image?>" alt="<?= $product->image->alt ? $product->image->alt : $product->name?>"> | |
13 | + <?php endif?> | |
14 | + </div> | |
8 | 15 | <div class="title_item"><?= $product->name?></div></a> |
9 | 16 | <div class="brand">Бренд: <span><?= $product->brand->name?></span></div> |
10 | 17 | <div class="type"><?= implode(', ', $product->categoriesNames)?></div> |
18 | + <?php if($product->variant) :?> | |
11 | 19 | <div class="price"><?= $product->variant->price?> <span>грн.</span></div> |
12 | 20 | <button class="basket_add_but" data-id="<?= $product->variant->product_variant_id?>">в корзину</button> |
21 | + <?php endif?> | |
13 | 22 | <a href="#" class="compare_add_but" data-id="<?= $product->product_id?>"><span>добавить к сравнению</span></a> |
14 | 23 | <img class="item_bottom_img" src="/images/nc_item_bottom.png" alt=""> |
15 | 24 | </div> |
16 | 25 | \ No newline at end of file | ... | ... |
frontend/views/catalog/products.php
... | ... | @@ -74,9 +74,9 @@ $this->params['breadcrumbs'][] = $category->name; |
74 | 74 | <li><?= $group->name?> |
75 | 75 | <div class="arrow"><img src="/images/head_down.png" alt=""></i></div> |
76 | 76 | <div class="price_filter"> |
77 | - <?php foreach($group->options as $option) :?> | |
77 | + <?php foreach($group->_options as $option) :?> | |
78 | 78 | <div class="checkbox"> |
79 | - <label><input type="checkbox" name="option[<?= $group->alias?>][]" value="<?= $option->alias?>" /></label> | |
79 | + <label><input type="checkbox" name="option[<?= $group->alias?>][]" value="<?= $option->alias?>"<?= (isset($options[$group->alias]) && in_array($option->alias, $options[$group->alias])) ? ' checked' : ''?> /></label> | |
80 | 80 | <a href="#"><?= $option->ValueRenderHTML?></a> |
81 | 81 | </div> |
82 | 82 | <?php endforeach?> | ... | ... |
23.4 KB
9.21 KB