diff --git a/.gitignore b/.gitignore
index 3973ae3..35f921c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,8 @@ common/config/params-local.php
backend/config/main-local.php
backend/config/params-local.php
frontend/config/main-local.php
-frontend/config/params-local.php
\ No newline at end of file
+frontend/config/params-local.php
+
+backend/web/assets/
+frontend/web/assets/
+frontend/web/css/node_modules/
\ No newline at end of file
diff --git a/backend/controllers/BrandController.php b/backend/controllers/BrandController.php
new file mode 100644
index 0000000..84ff5f6
--- /dev/null
+++ b/backend/controllers/BrandController.php
@@ -0,0 +1,123 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all Brand models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new BrandSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single Brand model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Brand model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Brand();
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return is_null(Yii::$app->request->post('create_and_new')) ? $this->redirect(['view', 'id' => $model->brand_id]) : $this->redirect(array_merge(['create'], Yii::$app->request->queryParams));
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing Brand model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->brand_id]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing Brand model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Brand model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Brand the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Brand::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/backend/controllers/CategoryController.php b/backend/controllers/CategoryController.php
new file mode 100644
index 0000000..6844d47
--- /dev/null
+++ b/backend/controllers/CategoryController.php
@@ -0,0 +1,132 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all Category models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new CategorySearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single Category model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Category model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Category();
+
+ if ($model->load(Yii::$app->request->post())) {
+ $model->save();
+ return is_null(Yii::$app->request->post('create_and_new')) ? $this->redirect(['view', 'id' => $model->category_id]) : $this->redirect(array_merge(['create'], Yii::$app->request->queryParams));
+ } else {
+ if (!empty(Yii::$app->request->queryParams['parent'])) {
+ $model->parent_id = Yii::$app->request->queryParams['parent'];
+ }
+ return $this->render('create', [
+ 'model' => $model,
+ 'categories' => ArtboxTreeHelper::treeMap(Category::find()->getTree(), 'category_id', 'name', '.')
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing Category model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->category_id]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ 'categories' => ArtboxTreeHelper::treeMap(Category::find()->getTree(), 'category_id', 'name', '.')
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing Category model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Category model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Category the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Category::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/backend/views/brand/_form.php b/backend/views/brand/_form.php
new file mode 100644
index 0000000..2d9c553
--- /dev/null
+++ b/backend/views/brand/_form.php
@@ -0,0 +1,51 @@
+
+
+
diff --git a/backend/views/brand/_search.php b/backend/views/brand/_search.php
new file mode 100644
index 0000000..967088a
--- /dev/null
+++ b/backend/views/brand/_search.php
@@ -0,0 +1,41 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'brand_id') ?>
+
+ = $form->field($model, 'brand_name_id') ?>
+
+ = $form->field($model, 'alias') ?>
+
+ = $form->field($model, 'image') ?>
+
+ = $form->field($model, 'meta_title') ?>
+
+ field($model, 'meta_desc') ?>
+
+ field($model, 'meta_robots') ?>
+
+ field($model, 'seo_text') ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/backend/views/brand/create.php b/backend/views/brand/create.php
new file mode 100644
index 0000000..e0d4833
--- /dev/null
+++ b/backend/views/brand/create.php
@@ -0,0 +1,21 @@
+title = Yii::t('product', 'Create Brand');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Brands'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/backend/views/brand/index.php b/backend/views/brand/index.php
new file mode 100644
index 0000000..b0a0619
--- /dev/null
+++ b/backend/views/brand/index.php
@@ -0,0 +1,33 @@
+title = Yii::t('product', 'Brands');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Brand'), ['create'], ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+// 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+
+ 'name',
+ 'alias',
+
+ ['class' => 'yii\grid\ActionColumn'],
+ ],
+ ]); ?>
+
diff --git a/backend/views/brand/update.php b/backend/views/brand/update.php
new file mode 100644
index 0000000..7b60ab0
--- /dev/null
+++ b/backend/views/brand/update.php
@@ -0,0 +1,23 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Brand',
+]) . ' ' . $model->brand_id;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Brands'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->brand_id, 'url' => ['view', 'id' => $model->brand_id]];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/backend/views/brand/view.php b/backend/views/brand/view.php
new file mode 100644
index 0000000..8180ef0
--- /dev/null
+++ b/backend/views/brand/view.php
@@ -0,0 +1,42 @@
+title = $model->brand_id;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Brands'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->brand_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->brand_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'brand_id',
+ 'brand_name_id',
+ 'alias',
+ 'image',
+ 'meta_title',
+ 'meta_desc:ntext',
+ 'meta_robots',
+ 'seo_text:ntext',
+ ],
+ ]) ?>
+
+
diff --git a/backend/views/category/_form.php b/backend/views/category/_form.php
new file mode 100644
index 0000000..ae860cf
--- /dev/null
+++ b/backend/views/category/_form.php
@@ -0,0 +1,63 @@
+
+
+
diff --git a/backend/views/category/_search.php b/backend/views/category/_search.php
new file mode 100644
index 0000000..f098041
--- /dev/null
+++ b/backend/views/category/_search.php
@@ -0,0 +1,49 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'category_id') ?>
+
+ = $form->field($model, 'parent_id') ?>
+
+ = $form->field($model, 'path') ?>
+
+ = $form->field($model, 'depth') ?>
+
+ = $form->field($model, 'image') ?>
+
+ field($model, 'meta_title') ?>
+
+ field($model, 'meta_desc') ?>
+
+ field($model, 'meta_robots') ?>
+
+ field($model, 'seo_text') ?>
+
+ field($model, 'category_name_id') ?>
+
+ field($model, 'product_unit_id') ?>
+
+ field($model, 'alias') ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/backend/views/category/create.php b/backend/views/category/create.php
new file mode 100644
index 0000000..9ca39fb
--- /dev/null
+++ b/backend/views/category/create.php
@@ -0,0 +1,22 @@
+title = Yii::t('product', 'Create Category');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Categories'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'categories' => $categories
+ ]) ?>
+
+
diff --git a/backend/views/category/index.php b/backend/views/category/index.php
new file mode 100644
index 0000000..876474e
--- /dev/null
+++ b/backend/views/category/index.php
@@ -0,0 +1,42 @@
+title = Yii::t('product', 'Categories');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Category'), ['create'], ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+// 'filterModel' => $searchModel,
+ 'columns' => [
+ [
+ 'label'=> Yii::t('rubrication', 'Name'),
+ 'content'=>function($data){
+ return str_repeat('-', $data->depth) .' '. $data->name;
+ }
+ ],
+ 'alias',
+ 'populary:boolean',
+ // 'meta_title',
+ // 'meta_desc:ntext',
+ // 'meta_robots',
+ // 'seo_text:ntext',
+ // 'product_unit_id',
+
+ ['class' => 'yii\grid\ActionColumn'],
+ ],
+ ]); ?>
+
diff --git a/backend/views/category/update.php b/backend/views/category/update.php
new file mode 100644
index 0000000..0f19387
--- /dev/null
+++ b/backend/views/category/update.php
@@ -0,0 +1,24 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Category',
+]) . ' ' . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Categories'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->category_id]];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'categories' => $categories
+ ]) ?>
+
+
diff --git a/backend/views/category/view.php b/backend/views/category/view.php
new file mode 100644
index 0000000..d68ed18
--- /dev/null
+++ b/backend/views/category/view.php
@@ -0,0 +1,50 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Categories'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->category_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->category_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+ = Html::a(Yii::t('product', 'Create category'), ['category/create'], ['class' => 'btn btn-success']) ?>
+ parent_id)) :?>
+ = Html::a(Yii::t('product', 'Create category By {name}', ['name' => $model->parent->name]), ['category/create?parent='. $model->parent->category_id], ['class' => 'btn btn-success']) ?>
+
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'category_id',
+ 'parent_id',
+ 'path',
+ 'depth',
+ 'image',
+ 'meta_title',
+ 'meta_desc:ntext',
+ 'meta_robots',
+ 'seo_text:ntext',
+ 'category_name_id',
+ 'product_unit_id',
+ 'alias',
+ ],
+ ]) ?>
+
+
diff --git a/backend/web/index-test.php b/backend/web/index-test.php
new file mode 100644
index 0000000..8b96707
--- /dev/null
+++ b/backend/web/index-test.php
@@ -0,0 +1,19 @@
+run();
diff --git a/backend/web/index.php b/backend/web/index.php
new file mode 100644
index 0000000..99030fa
--- /dev/null
+++ b/backend/web/index.php
@@ -0,0 +1,19 @@
+run();
diff --git a/common/modules/product/models/Brand.php b/common/modules/product/models/Brand.php
new file mode 100644
index 0000000..68e9d0e
--- /dev/null
+++ b/common/modules/product/models/Brand.php
@@ -0,0 +1,117 @@
+ [
+ 'class' => Slug::className(),
+ 'in_attribute' => 'name',
+ 'out_attribute' => 'alias',
+ 'translit' => true
+ ],
+ 'artboxsynonym' => [
+ 'class' => ArtboxSynonymBehavior::className(),
+ 'keyNameValue' => 'brand_name_id',
+ 'valueModel' => BrandName::className(),
+ 'valueOptionId' => 'brand_id',
+ 'valueFields' => [ // postKey => DBFieldName
+ 'name' => 'value'
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'brand';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['name'], 'required'],
+ [['brand_name_id'], 'integer'],
+ [['meta_desc', 'seo_text'], 'string'],
+ [['alias', 'name'], 'string', 'max' => 250],
+ [['image', 'meta_title'], 'string', 'max' => 255],
+ [['meta_robots'], 'string', 'max' => 50],
+// [['brand_name_id'], 'exist', 'skipOnError' => true, 'targetClass' => BrandName::className(), 'targetAttribute' => ['brand_name_id' => 'brand_name_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'brand_id' => Yii::t('product', 'Brand ID'),
+ 'brand_name_id' => Yii::t('product', 'Brand Name ID'),
+ 'alias' => Yii::t('product', 'Alias'),
+ 'image' => Yii::t('product', 'Image'),
+ 'meta_title' => Yii::t('product', 'Meta Title'),
+ 'meta_desc' => Yii::t('product', 'Meta Desc'),
+ 'meta_robots' => Yii::t('product', 'Meta Robots'),
+ 'seo_text' => Yii::t('product', 'Seo Text'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrandName()
+ {
+ return $this->hasOne(BrandName::className(), ['brand_name_id' => 'brand_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrandNames()
+ {
+ return $this->hasMany(BrandName::className(), ['brand_id' => 'brand_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProducts()
+ {
+ return $this->hasMany(Product::className(), ['brand_id' => 'brand_id']);
+ }
+
+ public function getName() {
+ $value = $this->getBrandName()->one();
+ return empty($value) ? $this->_getValue('name') : $value->value;
+ }
+}
diff --git a/common/modules/product/models/BrandName.php b/common/modules/product/models/BrandName.php
new file mode 100644
index 0000000..5bab547
--- /dev/null
+++ b/common/modules/product/models/BrandName.php
@@ -0,0 +1,66 @@
+ 250],
+// [['brand_id'], 'exist', 'skipOnError' => true, 'targetClass' => Brand::className(), 'targetAttribute' => ['brand_id' => 'brand_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'brand_name_id' => Yii::t('product', 'Brand Name ID'),
+ 'brand_id' => Yii::t('product', 'Brand ID'),
+ 'value' => Yii::t('product', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrands()
+ {
+ return $this->hasMany(Brand::className(), ['brand_name_id' => 'brand_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrand()
+ {
+ return $this->hasOne(Brand::className(), ['brand_id' => 'brand_id']);
+ }
+}
diff --git a/common/modules/product/models/BrandQuery.php b/common/modules/product/models/BrandQuery.php
new file mode 100644
index 0000000..a0d1273
--- /dev/null
+++ b/common/modules/product/models/BrandQuery.php
@@ -0,0 +1,34 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Brand[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Brand|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/product/models/BrandSearch.php b/common/modules/product/models/BrandSearch.php
new file mode 100644
index 0000000..0fb516f
--- /dev/null
+++ b/common/modules/product/models/BrandSearch.php
@@ -0,0 +1,75 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ /*if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }*/
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'brand_id' => $this->brand_id,
+ 'brand_name_id' => $this->brand_name_id,
+ ]);
+
+ $query->andFilterWhere(['like', 'alias', $this->alias])
+ ->andFilterWhere(['like', 'image', $this->image])
+ ->andFilterWhere(['like', 'meta_title', $this->meta_title])
+ ->andFilterWhere(['like', 'meta_desc', $this->meta_desc])
+ ->andFilterWhere(['like', 'meta_robots', $this->meta_robots])
+ ->andFilterWhere(['like', 'seo_text', $this->seo_text]);
+
+ return $dataProvider;
+ }
+}
diff --git a/common/modules/product/models/Category.php b/common/modules/product/models/Category.php
new file mode 100644
index 0000000..2b5be1b
--- /dev/null
+++ b/common/modules/product/models/Category.php
@@ -0,0 +1,153 @@
+ [
+ 'class' => ArtboxTreeBehavior::className(),
+ 'keyNameGroup' => null,
+ 'keyNamePath' => 'path',
+ ],
+ 'slug' => [
+ 'class' => Slug::className(),
+ 'in_attribute' => 'name',
+ 'out_attribute' => 'alias',
+ 'translit' => true
+ ],
+ 'artboxsynonym' => [
+ 'class' => ArtboxSynonymBehavior::className(),
+ 'keyNameValue' => 'category_name_id',
+ 'valueModel' => CategoryName::className(),
+ 'valueOptionId' => 'category_id',
+ 'valueFields' => [ // postKey => DBFieldName
+ 'name' => 'value'
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'category';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['name'], 'required'],
+ [['parent_id', 'depth', 'category_name_id', 'product_unit_id'], 'integer'],
+ [['path', 'meta_desc', 'seo_text'], 'string'],
+ [['image', 'meta_title'], 'string', 'max' => 255],
+ [['meta_robots'], 'string', 'max' => 50],
+ [['alias', 'name'], 'string', 'max' => 250],
+ [['populary'], 'boolean']
+// [['product_unit_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductUnit::className(), 'targetAttribute' => ['product_unit_id' => 'product_unit_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'category_id' => Yii::t('product', 'Category ID'),
+ 'parent_id' => Yii::t('product', 'Parent ID'),
+ 'path' => Yii::t('product', 'Path'),
+ 'depth' => Yii::t('product', 'Depth'),
+ 'image' => Yii::t('product', 'Image'),
+ 'meta_title' => Yii::t('product', 'Meta Title'),
+ 'meta_desc' => Yii::t('product', 'Meta Desc'),
+ 'meta_robots' => Yii::t('product', 'Meta Robots'),
+ 'seo_text' => Yii::t('product', 'Seo Text'),
+ 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
+ 'alias' => Yii::t('product', 'Alias'),
+ 'populary' => Yii::t('product', 'Populary'),
+ ];
+ }
+
+ public static function find() {
+ return new CategoryQuery(get_called_class());
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductUnit()
+ {
+ return $this->hasOne(ProductUnit::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategoryNames()
+ {
+ return $this->hasMany(CategoryName::className(), ['category_id' => 'category_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductCategories()
+ {
+ return $this->hasMany(ProductCategory::className(), ['category_id' => 'category_id']);
+ }
+
+ public function beforeSave($insert)
+ {
+ if (parent::beforeSave($insert)) {
+
+ if (empty($this->parent_id))
+ $this->parent_id = 0;
+ return true;
+ }
+ return false;
+ }
+
+ public function getCategoryName() {
+ return $this->hasOne(CategoryName::className(), ['category_name_id' => 'category_name_id']);
+ }
+
+ public function getName() {
+ $value = $this->getCategoryName()->one();
+ return empty($value) ? $this->_getValue('name') : $value->value;
+ }
+}
diff --git a/common/modules/product/models/CategoryName.php b/common/modules/product/models/CategoryName.php
new file mode 100644
index 0000000..6c84f3e
--- /dev/null
+++ b/common/modules/product/models/CategoryName.php
@@ -0,0 +1,66 @@
+ 250],
+ [['category_id'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['category_id' => 'category_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'category_name_id' => Yii::t('product', 'Category Name ID'),
+ 'category_id' => Yii::t('product', 'Category ID'),
+ 'value' => Yii::t('product', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategories()
+ {
+ return $this->hasMany(Category::className(), ['category_name_id' => 'category_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategory()
+ {
+ return $this->hasOne(Category::className(), ['category_id' => 'category_id']);
+ }
+}
diff --git a/common/modules/product/models/CategoryQuery.php b/common/modules/product/models/CategoryQuery.php
new file mode 100644
index 0000000..069d8e7
--- /dev/null
+++ b/common/modules/product/models/CategoryQuery.php
@@ -0,0 +1,48 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Category[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Category|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+
+ /**
+ * Select category by alias
+ * @param $slug
+ * @return $this
+ */
+ public function byAlias($alias)
+ {
+ $this->andFilterWhere(['alias' => $alias]);
+ return $this;
+ }
+}
diff --git a/common/modules/product/models/CategorySearch.php b/common/modules/product/models/CategorySearch.php
new file mode 100644
index 0000000..ae60343
--- /dev/null
+++ b/common/modules/product/models/CategorySearch.php
@@ -0,0 +1,99 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ /*if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }*/
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'category_id' => $this->category_id,
+ 'parent_id' => $this->parent_id,
+ 'category_name_id' => $this->category_name_id,
+ 'product_unit_id' => $this->product_unit_id,
+ ]);
+
+ $query->andFilterWhere(['like', 'alias', $this->alias]);
+
+ $query->orderBy(['path' => SORT_ASC, 'depth' => SORT_ASC]);
+
+ return $dataProvider;
+ }
+
+ public static function findByAlias($alias) {
+ /** @var CategoryQuery $query */
+ $query = Category::find();
+ $query->byAlias($alias);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/models/ProductUnit.php b/common/modules/product/models/ProductUnit.php
new file mode 100644
index 0000000..6b5eaff
--- /dev/null
+++ b/common/modules/product/models/ProductUnit.php
@@ -0,0 +1,69 @@
+ 255],
+ [['code'], 'string', 'max' => 50],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
+ 'name' => Yii::t('product', 'Name'),
+ 'code' => Yii::t('product', 'Code'),
+ 'is_default' => Yii::t('product', 'Is Default'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategories()
+ {
+ return $this->hasMany(Category::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariants()
+ {
+ return $this->hasMany(ProductVariant::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+}
diff --git a/common/modules/product/widgets/catalogSubmenuWidget.php b/common/modules/product/widgets/catalogSubmenuWidget.php
new file mode 100644
index 0000000..a3cb377
--- /dev/null
+++ b/common/modules/product/widgets/catalogSubmenuWidget.php
@@ -0,0 +1,26 @@
+root_id);
+ return $this->render('submenu', [
+ 'rootCategory' => $rootCategory,
+ 'rootClass' => $this->rootClass,
+ 'populary' => $rootCategory->getAllChildren(2, ['populary' => true])->all(),
+ 'items' => $rootCategory->getAllChildrenTree(2)
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/rubrication/models/TaxValueFloat.php b/common/modules/rubrication/models/TaxValueFloat.php
new file mode 100644
index 0000000..df79b56
--- /dev/null
+++ b/common/modules/rubrication/models/TaxValueFloat.php
@@ -0,0 +1,58 @@
+ true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['tax_option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_value_id' => Yii::t('app', 'Tax Value ID'),
+ 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
+ 'value' => Yii::t('app', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxValues');
+ }
+}
diff --git a/common/modules/rubrication/views/tax-option/value/_fields_float.php b/common/modules/rubrication/views/tax-option/value/_fields_float.php
new file mode 100644
index 0000000..6a35b2f
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/value/_fields_float.php
@@ -0,0 +1 @@
+= $form->field($valueModel, 'value')->textInput() ?>
\ No newline at end of file
diff --git a/frontend/controllers/CatalogController.php b/frontend/controllers/CatalogController.php
new file mode 100644
index 0000000..de8f8dd
--- /dev/null
+++ b/frontend/controllers/CatalogController.php
@@ -0,0 +1,53 @@
+depth < 2) {
+ return $this->render(
+ 'categories',
+ [
+ 'category' => $category
+ ]
+ );
+ } else {
+
+ return $this->render(
+ 'products',
+ [
+ 'category' => $category,
+ ]
+ );
+ }
+ }
+
+ public function actionProduct($alias)
+ {
+ $product = Product::find()->where('like', ['alias' => $alias]);
+ if (empty($product->product_id)) {
+// throw new HttpException(404 ,'Page not found');
+// return $this->redirect('/', 301);
+ }
+ return $this->render('product');
+ }
+
+ public function actionBrands()
+ {
+ return 'actionBrands';
+ }
+
+ public function actionBrand($alias)
+ {
+ return 'actionBrand:'. $alias;
+ }
+
+}
diff --git a/frontend/views/catalog/categories.php b/frontend/views/catalog/categories.php
new file mode 100644
index 0000000..84406f7
--- /dev/null
+++ b/frontend/views/catalog/categories.php
@@ -0,0 +1,45 @@
+title = $category->name;
+foreach($category->getParents()->all() as $parent) {
+ $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'alias' => $parent->alias]];
+}
+$this->params['breadcrumbs'][] = $this->title;
+?>
+= $this->title ?>
+
+
+
+
+
+ getAllChildrenTree(2) as $category) :?>
+
+
+ image)) :?>
+
![<?= $category['item']->name?>](<?= $category['item']->image?>)
+
+

+
+
= $category['item']->name?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
--
libgit2 0.21.4