Commit 2f25da0966476d00ec3396e22f80b5236505ea9c
0 parents
first commit
Showing
133 changed files
with
16624 additions
and
0 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 133 files are displayed.
artbox-blog @ 6813d2d0b71
artbox-comment @ a2cde075db9
1 | +++ a/artbox-ecommerce/Module.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce; | |
4 | + | |
5 | + /** | |
6 | + * product module definition class | |
7 | + */ | |
8 | + class Module extends \yii\base\Module | |
9 | + { | |
10 | + | |
11 | + public $types = []; | |
12 | + | |
13 | + /** | |
14 | + * @inheritdoc | |
15 | + */ | |
16 | + public function init() | |
17 | + { | |
18 | + parent::init(); | |
19 | + | |
20 | + \Yii::configure($this, require( __DIR__ . '/config.php' )); | |
21 | + } | |
22 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/behaviors/FilterBehavior.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\behaviors; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\ProductOption; | |
6 | + use artweb\artbox\ecommerce\models\TaxOption; | |
7 | + use yii\base\Behavior; | |
8 | + use yii\db\ActiveRecord; | |
9 | + | |
10 | + class FilterBehavior extends Behavior | |
11 | + { | |
12 | + | |
13 | + public function getFilters() | |
14 | + { | |
15 | + | |
16 | + /** | |
17 | + * @var ActiveRecord $owner | |
18 | + */ | |
19 | + $owner = $this->owner; | |
20 | + return $owner->hasMany(TaxOption::className(), [ 'tax_option_id' => 'option_id' ]) | |
21 | + ->viaTable(ProductOption::tableName(), [ 'product_id' => $owner->getTableSchema()->primaryKey[ 0 ] ]) | |
22 | + ->joinWith('taxGroup') | |
23 | + ->all(); | |
24 | + } | |
25 | + | |
26 | + } | |
0 | 27 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/composer.json | |
1 | +{ | |
2 | + "name": "artweb/artbox-ecommerce", | |
3 | + "description": "Yii2 light-weight CMS", | |
4 | + "license": "BSD-3-Clause", | |
5 | + "require": { | |
6 | + "php": ">=7.0", | |
7 | + "yiisoft/yii2": "*", | |
8 | + "developeruz/yii2-db-rbac": "*" | |
9 | + }, | |
10 | + "autoload": { | |
11 | + "psr-4": { | |
12 | + "artweb\\artbox\\ecommerce\\": "" | |
13 | + } | |
14 | + } | |
15 | +} | |
0 | 16 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/controllers/ManageController.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\controllers; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use artweb\artbox\ecommerce\models\Export; | |
7 | + use artweb\artbox\ecommerce\models\Import; | |
8 | + use artweb\artbox\ecommerce\models\ProductImage; | |
9 | + use Yii; | |
10 | + use artweb\artbox\ecommerce\models\Product; | |
11 | + use artweb\artbox\ecommerce\models\ProductSearch; | |
12 | + use yii\db\ActiveQuery; | |
13 | + use yii\web\Controller; | |
14 | + use yii\web\NotFoundHttpException; | |
15 | + use yii\filters\VerbFilter; | |
16 | + use yii\web\Response; | |
17 | + use yii\web\UploadedFile; | |
18 | + | |
19 | + /** | |
20 | + * ManageController implements the CRUD actions for Product model. | |
21 | + */ | |
22 | + class ManageController extends Controller | |
23 | + { | |
24 | + | |
25 | + /** | |
26 | + * @inheritdoc | |
27 | + */ | |
28 | + public function behaviors() | |
29 | + { | |
30 | + return [ | |
31 | + 'verbs' => [ | |
32 | + 'class' => VerbFilter::className(), | |
33 | + 'actions' => [ | |
34 | + 'delete' => [ 'POST' ], | |
35 | + ], | |
36 | + ], | |
37 | + ]; | |
38 | + } | |
39 | + | |
40 | + /** | |
41 | + * Lists all Product models. | |
42 | + * | |
43 | + * @return mixed | |
44 | + */ | |
45 | + public function actionIndex() | |
46 | + { | |
47 | + $searchModel = new ProductSearch(); | |
48 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | |
49 | + | |
50 | + return $this->render( | |
51 | + 'index', | |
52 | + [ | |
53 | + 'searchModel' => $searchModel, | |
54 | + 'dataProvider' => $dataProvider, | |
55 | + ] | |
56 | + ); | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * Displays a single Product model. | |
61 | + * | |
62 | + * @param integer $id | |
63 | + * | |
64 | + * @return mixed | |
65 | + */ | |
66 | + public function actionView($id) | |
67 | + { | |
68 | + $model = $this->findModel($id); | |
69 | + $categories = $model->getCategories() | |
70 | + ->with('lang') | |
71 | + ->all(); | |
72 | + $variants = $model->getVariants() | |
73 | + ->with('lang') | |
74 | + ->all(); | |
75 | + $properties = $model->getProperties(); | |
76 | + return $this->render( | |
77 | + 'view', | |
78 | + [ | |
79 | + 'model' => $this->findModel($id), | |
80 | + 'categories' => $categories, | |
81 | + 'variants' => $variants, | |
82 | + 'properties' => $properties, | |
83 | + ] | |
84 | + ); | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * Creates a new Product model. | |
89 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
90 | + * | |
91 | + * @return mixed | |
92 | + */ | |
93 | + public function actionCreate() | |
94 | + { | |
95 | + $model = new Product(); | |
96 | + $model->generateLangs(); | |
97 | + if ($model->load(Yii::$app->request->post())) { | |
98 | + $model->loadLangs(\Yii::$app->request); | |
99 | + if ($model->save() && $model->transactionStatus) { | |
100 | + return $this->redirect( | |
101 | + [ | |
102 | + 'view', | |
103 | + 'id' => $model->id, | |
104 | + ] | |
105 | + ); | |
106 | + } | |
107 | + } | |
108 | + return $this->render( | |
109 | + 'create', | |
110 | + [ | |
111 | + 'model' => $model, | |
112 | + 'modelLangs' => $model->modelLangs, | |
113 | + ] | |
114 | + ); | |
115 | + } | |
116 | + | |
117 | + /** | |
118 | + * Updates an existing Product model. | |
119 | + * If update is successful, the browser will be redirected to the 'view' page. | |
120 | + * | |
121 | + * @param integer $id | |
122 | + * | |
123 | + * @return mixed | |
124 | + */ | |
125 | + public function actionUpdate($id) | |
126 | + { | |
127 | + $model = $this->findModel($id); | |
128 | + $model->generateLangs(); | |
129 | + if ($model->load(Yii::$app->request->post())) { | |
130 | + $model->loadLangs(\Yii::$app->request); | |
131 | + if ($model->save() && $model->transactionStatus) { | |
132 | + return $this->redirect( | |
133 | + [ | |
134 | + 'view', | |
135 | + 'id' => $model->id, | |
136 | + ] | |
137 | + ); | |
138 | + } | |
139 | + } | |
140 | + /** | |
141 | + * @var ActiveQuery $groups | |
142 | + */ | |
143 | + $groups = $model->getTaxGroupsByLevel(0); | |
144 | + return $this->render( | |
145 | + 'update', | |
146 | + [ | |
147 | + 'model' => $model, | |
148 | + 'modelLangs' => $model->modelLangs, | |
149 | + 'groups' => $groups, | |
150 | + ] | |
151 | + ); | |
152 | + } | |
153 | + | |
154 | + /** | |
155 | + * Deletes an existing Product model. | |
156 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
157 | + * | |
158 | + * @param integer $id | |
159 | + * | |
160 | + * @return mixed | |
161 | + */ | |
162 | + public function actionDelete($id) | |
163 | + { | |
164 | + $this->findModel($id) | |
165 | + ->delete(); | |
166 | + return $this->redirect([ 'index' ]); | |
167 | + } | |
168 | + | |
169 | + /** | |
170 | + * Deletes an existing ProductImage model. | |
171 | + * | |
172 | + * @param int $id | |
173 | + */ | |
174 | + public function actionDeleteImage($id) | |
175 | + { | |
176 | + $image = ProductImage::findOne($id); | |
177 | + | |
178 | + if ($image) { | |
179 | + $image->delete(); | |
180 | + } | |
181 | + | |
182 | + print '1'; | |
183 | + exit; | |
184 | + } | |
185 | + | |
186 | + /** | |
187 | + * Toggle product top status | |
188 | + * | |
189 | + * @param int $id Product ID | |
190 | + * | |
191 | + * @return \yii\web\Response | |
192 | + */ | |
193 | + public function actionIsTop($id) | |
194 | + { | |
195 | + $model = $this->findModel($id); | |
196 | + | |
197 | + $model->is_top = intval(empty( $model->is_top )); | |
198 | + | |
199 | + $model->save(false, [ 'is_top' ]); | |
200 | + | |
201 | + return $this->redirect([ 'index' ]); | |
202 | + } | |
203 | + | |
204 | + /** | |
205 | + * Toggle product new status | |
206 | + * | |
207 | + * @param int $id Product ID | |
208 | + * | |
209 | + * @return \yii\web\Response | |
210 | + */ | |
211 | + public function actionIsNew($id) | |
212 | + { | |
213 | + $model = $this->findModel($id); | |
214 | + | |
215 | + $model->is_new = intval(empty( $model->is_new )); | |
216 | + | |
217 | + $model->save(false, [ 'is_new' ]); | |
218 | + | |
219 | + return $this->redirect([ 'index' ]); | |
220 | + } | |
221 | + | |
222 | + /** | |
223 | + * Toggle product discount status | |
224 | + * | |
225 | + * @param int $id Product ID | |
226 | + * | |
227 | + * @return \yii\web\Response | |
228 | + */ | |
229 | + public function actionIsDiscount($id) | |
230 | + { | |
231 | + $model = $this->findModel($id); | |
232 | + | |
233 | + $model->is_discount = intval(empty( $model->is_discount )); | |
234 | + | |
235 | + $model->save(false, [ 'is_discount' ]); | |
236 | + | |
237 | + return $this->redirect([ 'index' ]); | |
238 | + } | |
239 | + | |
240 | + /** | |
241 | + * Perform product import | |
242 | + * | |
243 | + * @return string | |
244 | + */ | |
245 | + public function actionImport() | |
246 | + { | |
247 | + $model = new Import(); | |
248 | + | |
249 | + $languages = Language::find() | |
250 | + ->select( | |
251 | + [ | |
252 | + 'name', | |
253 | + 'id', | |
254 | + ] | |
255 | + ) | |
256 | + ->where([ 'status' => 1 ]) | |
257 | + ->orderBy([ 'default' => SORT_DESC ]) | |
258 | + ->asArray() | |
259 | + ->indexBy('id') | |
260 | + ->column(); | |
261 | + | |
262 | + if ($model->load(Yii::$app->request->post())) { | |
263 | + \Yii::$app->session->set('export_lang', $model->lang); | |
264 | + $file = UploadedFile::getInstances($model, 'file'); | |
265 | + $method = 'go' . ucfirst($model->type); | |
266 | + $target = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFile' . ucfirst($model->type)); | |
267 | + if (empty( $file )) { | |
268 | + $model->errors[] = 'File not upload'; | |
269 | + } elseif ($method == 'goPrices' && $file[ 0 ]->name != 'file_1.csv') { | |
270 | + $model->errors[] = 'File need "file_1.csv"'; | |
271 | + } elseif ($method == 'goProducts' && $file[ 0 ]->name == 'file_1.csv') { | |
272 | + $model->errors[] = 'File can not "file_1.csv"'; | |
273 | + } elseif ($model->validate() && $file[ 0 ]->saveAs($target)) { | |
274 | + // PROCESS PAGE | |
275 | + return $this->render( | |
276 | + 'import-process', | |
277 | + [ | |
278 | + 'model' => $model, | |
279 | + 'method' => $model->type, | |
280 | + 'target' => $target, | |
281 | + ] | |
282 | + ); | |
283 | + } else { | |
284 | + $model->errors[] = 'File can not be upload or other error'; | |
285 | + } | |
286 | + } | |
287 | + | |
288 | + return $this->render( | |
289 | + 'import', | |
290 | + [ | |
291 | + 'model' => $model, | |
292 | + 'languages' => $languages, | |
293 | + ] | |
294 | + ); | |
295 | + } | |
296 | + | |
297 | + /** | |
298 | + * Import products via AJAX | |
299 | + * | |
300 | + * @return array | |
301 | + * @throws \HttpRequestException | |
302 | + */ | |
303 | + public function actionProducts() | |
304 | + { | |
305 | + $from = Yii::$app->request->get('from', 0); | |
306 | + | |
307 | + $model = new Import(); | |
308 | + | |
309 | + if (Yii::$app->request->isAjax) { | |
310 | + Yii::$app->response->format = Response::FORMAT_JSON; | |
311 | + return $model->goProducts($from, 1); | |
312 | + } else { | |
313 | + throw new \HttpRequestException('Must be AJAX'); | |
314 | + } | |
315 | + } | |
316 | + | |
317 | + /** | |
318 | + * Import prices via AJAX | |
319 | + * | |
320 | + * @return array | |
321 | + * @throws \HttpRequestException | |
322 | + */ | |
323 | + public function actionPrices() | |
324 | + { | |
325 | + $from = Yii::$app->request->get('from', 0); | |
326 | + | |
327 | + $model = new Import(); | |
328 | + | |
329 | + if (Yii::$app->request->isAjax) { | |
330 | + Yii::$app->response->format = Response::FORMAT_JSON; | |
331 | + return $model->goPrices($from, 10); | |
332 | + } else { | |
333 | + throw new \HttpRequestException('Must be AJAX'); | |
334 | + } | |
335 | + } | |
336 | + | |
337 | + /** | |
338 | + * Export proccess via AJAX | |
339 | + * | |
340 | + * @param int $from | |
341 | + * @param string $filename | |
342 | + * | |
343 | + * @return array | |
344 | + * @throws \HttpRequestException | |
345 | + */ | |
346 | + public function actionExportProcess($from, $filename) | |
347 | + { | |
348 | + | |
349 | + $model = new Export(); | |
350 | + if (Yii::$app->request->isAjax) { | |
351 | + Yii::$app->response->format = Response::FORMAT_JSON; | |
352 | + return $model->process($filename, $from); | |
353 | + } else { | |
354 | + throw new \HttpRequestException('Must be AJAX'); | |
355 | + } | |
356 | + } | |
357 | + | |
358 | + /** | |
359 | + * Perform export | |
360 | + * | |
361 | + * @return string | |
362 | + */ | |
363 | + public function actionExport() | |
364 | + { | |
365 | + $model = new Export(); | |
366 | + | |
367 | + if ($model->load(Yii::$app->request->post())) { | |
368 | + \Yii::$app->session->set('export_lang', $model->lang); | |
369 | + return $this->render( | |
370 | + 'export-process', | |
371 | + [ | |
372 | + 'model' => $model, | |
373 | + 'method' => 'export', | |
374 | + ] | |
375 | + ); | |
376 | + } | |
377 | + | |
378 | + return $this->render( | |
379 | + 'export', | |
380 | + [ | |
381 | + 'model' => $model, | |
382 | + ] | |
383 | + ); | |
384 | + } | |
385 | + | |
386 | + /** | |
387 | + * Finds the Product model based on its primary key value. | |
388 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
389 | + * | |
390 | + * @param integer $id | |
391 | + * | |
392 | + * @return Product the loaded model | |
393 | + * @throws NotFoundHttpException if the model cannot be found | |
394 | + */ | |
395 | + protected function findModel($id) | |
396 | + { | |
397 | + if (( $model = Product::find() | |
398 | + ->where([ 'id' => $id ]) | |
399 | + ->with('lang') | |
400 | + ->one() ) !== null | |
401 | + ) { | |
402 | + return $model; | |
403 | + } else { | |
404 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
405 | + } | |
406 | + } | |
407 | + } | ... | ... |
artbox-ecommerce/controllers/ProductUnitController.php
0 → 100755
1 | +++ a/artbox-ecommerce/controllers/ProductUnitController.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\controllers; | |
4 | + | |
5 | + use Yii; | |
6 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
7 | + use artweb\artbox\ecommerce\models\ProductUnitSearch; | |
8 | + use yii\web\Controller; | |
9 | + use yii\web\NotFoundHttpException; | |
10 | + use yii\filters\VerbFilter; | |
11 | + | |
12 | + /** | |
13 | + * ProductUnitController implements the CRUD actions for ProductUnit model. | |
14 | + */ | |
15 | + class ProductUnitController extends Controller | |
16 | + { | |
17 | + | |
18 | + /** | |
19 | + * @inheritdoc | |
20 | + */ | |
21 | + public function behaviors() | |
22 | + { | |
23 | + return [ | |
24 | + 'verbs' => [ | |
25 | + 'class' => VerbFilter::className(), | |
26 | + 'actions' => [ | |
27 | + 'delete' => [ 'POST' ], | |
28 | + ], | |
29 | + ], | |
30 | + ]; | |
31 | + } | |
32 | + | |
33 | + /** | |
34 | + * Lists all ProductUnit models. | |
35 | + * | |
36 | + * @return mixed | |
37 | + */ | |
38 | + public function actionIndex() | |
39 | + { | |
40 | + $searchModel = new ProductUnitSearch(); | |
41 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | |
42 | + | |
43 | + return $this->render( | |
44 | + 'index', | |
45 | + [ | |
46 | + 'searchModel' => $searchModel, | |
47 | + 'dataProvider' => $dataProvider, | |
48 | + ] | |
49 | + ); | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * Displays a single ProductUnit model. | |
54 | + * | |
55 | + * @param integer $id | |
56 | + * | |
57 | + * @return mixed | |
58 | + */ | |
59 | + public function actionView($id) | |
60 | + { | |
61 | + return $this->render( | |
62 | + 'view', | |
63 | + [ | |
64 | + 'model' => $this->findModel($id), | |
65 | + ] | |
66 | + ); | |
67 | + } | |
68 | + | |
69 | + /** | |
70 | + * Creates a new ProductUnit model. | |
71 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
72 | + * | |
73 | + * @return mixed | |
74 | + */ | |
75 | + public function actionCreate() | |
76 | + { | |
77 | + $model = new ProductUnit(); | |
78 | + $model->generateLangs(); | |
79 | + if ($model->load(Yii::$app->request->post())) { | |
80 | + $model->loadLangs(\Yii::$app->request); | |
81 | + if ($model->save() && $model->transactionStatus) { | |
82 | + return $this->redirect( | |
83 | + [ | |
84 | + 'view', | |
85 | + 'id' => $model->id, | |
86 | + ] | |
87 | + ); | |
88 | + } | |
89 | + } | |
90 | + return $this->render( | |
91 | + 'create', | |
92 | + [ | |
93 | + 'model' => $model, | |
94 | + 'modelLangs' => $model->modelLangs, | |
95 | + ] | |
96 | + ); | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * Updates an existing ProductUnit model. | |
101 | + * If update is successful, the browser will be redirected to the 'view' page. | |
102 | + * | |
103 | + * @param integer $id | |
104 | + * | |
105 | + * @return mixed | |
106 | + */ | |
107 | + public function actionUpdate($id) | |
108 | + { | |
109 | + $model = $this->findModel($id); | |
110 | + $model->generateLangs(); | |
111 | + if ($model->load(Yii::$app->request->post())) { | |
112 | + $model->loadLangs(\Yii::$app->request); | |
113 | + if ($model->save() && $model->transactionStatus) { | |
114 | + return $this->redirect( | |
115 | + [ | |
116 | + 'view', | |
117 | + 'id' => $model->id, | |
118 | + ] | |
119 | + ); | |
120 | + } | |
121 | + } | |
122 | + return $this->render( | |
123 | + 'update', | |
124 | + [ | |
125 | + 'model' => $model, | |
126 | + 'modelLangs' => $model->modelLangs, | |
127 | + ] | |
128 | + ); | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * Deletes an existing ProductUnit model. | |
133 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
134 | + * | |
135 | + * @param integer $id | |
136 | + * | |
137 | + * @return mixed | |
138 | + */ | |
139 | + public function actionDelete($id) | |
140 | + { | |
141 | + $this->findModel($id) | |
142 | + ->delete(); | |
143 | + | |
144 | + return $this->redirect([ 'index' ]); | |
145 | + } | |
146 | + | |
147 | + /** | |
148 | + * Finds the ProductUnit model based on its primary key value. | |
149 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
150 | + * | |
151 | + * @param integer $id | |
152 | + * | |
153 | + * @return ProductUnit the loaded model | |
154 | + * @throws NotFoundHttpException if the model cannot be found | |
155 | + */ | |
156 | + protected function findModel($id) | |
157 | + { | |
158 | + if (( $model = ProductUnit::find() | |
159 | + ->where([ 'id' => $id ]) | |
160 | + ->with('lang') | |
161 | + ->one() ) !== null | |
162 | + ) { | |
163 | + return $model; | |
164 | + } else { | |
165 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
166 | + } | |
167 | + } | |
168 | + } | ... | ... |
artbox-ecommerce/controllers/TaxGroupController.php
0 → 100755
1 | +++ a/artbox-ecommerce/controllers/TaxGroupController.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\controllers; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\TaxGroupSearch; | |
6 | + use Yii; | |
7 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
8 | + use yii\data\ActiveDataProvider; | |
9 | + use yii\db\ActiveQuery; | |
10 | + use yii\web\Controller; | |
11 | + use yii\web\NotFoundHttpException; | |
12 | + use yii\filters\VerbFilter; | |
13 | + | |
14 | + /** | |
15 | + * TaxGroupController implements the CRUD actions for TaxGroup model. | |
16 | + */ | |
17 | + class TaxGroupController extends Controller | |
18 | + { | |
19 | + | |
20 | + /** | |
21 | + * @inheritdoc | |
22 | + */ | |
23 | + public function behaviors() | |
24 | + { | |
25 | + return [ | |
26 | + 'verbs' => [ | |
27 | + 'class' => VerbFilter::className(), | |
28 | + 'actions' => [ | |
29 | + 'delete' => [ 'POST' ], | |
30 | + ], | |
31 | + ], | |
32 | + ]; | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * Lists all TaxGroup models. | |
37 | + * | |
38 | + * @param $level integer | |
39 | + * | |
40 | + * @return mixed | |
41 | + */ | |
42 | + public function actionIndex($level) | |
43 | + { | |
44 | + $searchModel = new TaxGroupSearch(); | |
45 | + $dataProvider = $searchModel->search(\Yii::$app->request->queryParams, $level); | |
46 | + /** | |
47 | + * @var ActiveQuery $query | |
48 | + */ | |
49 | + $query = $dataProvider->query; | |
50 | + $query->with('options') | |
51 | + ->with('categories'); | |
52 | + | |
53 | + return $this->render( | |
54 | + 'index', | |
55 | + [ | |
56 | + 'dataProvider' => $dataProvider, | |
57 | + 'searchModel' => $searchModel, | |
58 | + 'level' => $level, | |
59 | + ] | |
60 | + ); | |
61 | + } | |
62 | + | |
63 | + /** | |
64 | + * Creates a new TaxGroup model. | |
65 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
66 | + * | |
67 | + * @param $level integer | |
68 | + * | |
69 | + * @return mixed | |
70 | + */ | |
71 | + public function actionCreate($level) | |
72 | + { | |
73 | + $model = new TaxGroup(); | |
74 | + $model->generateLangs(); | |
75 | + if ($model->load(Yii::$app->request->post()) && $model->validate()) { | |
76 | + $model->loadLangs(\Yii::$app->request); | |
77 | + $model->level = $level; | |
78 | + if ($model->save() && $model->transactionStatus) { | |
79 | + return $this->redirect( | |
80 | + [ | |
81 | + 'index', | |
82 | + 'level' => $level, | |
83 | + ] | |
84 | + ); | |
85 | + } | |
86 | + } | |
87 | + return $this->render( | |
88 | + 'create', | |
89 | + [ | |
90 | + 'model' => $model, | |
91 | + 'modelLangs' => $model->modelLangs, | |
92 | + ] | |
93 | + ); | |
94 | + } | |
95 | + | |
96 | + /** | |
97 | + * Updates an existing TaxGroup model. | |
98 | + * If update is successful, the browser will be redirected to the 'view' page. | |
99 | + * | |
100 | + * @param $level integer | |
101 | + * @param integer $id | |
102 | + * | |
103 | + * @return mixed | |
104 | + */ | |
105 | + public function actionUpdate($level, $id) | |
106 | + { | |
107 | + $model = $this->findModel($id); | |
108 | + $model->generateLangs(); | |
109 | + if ($model->load(Yii::$app->request->post())) { | |
110 | + $model->loadLangs(\Yii::$app->request); | |
111 | + if ($model->save() && $model->transactionStatus) { | |
112 | + return $this->redirect( | |
113 | + [ | |
114 | + 'index', | |
115 | + 'level' => $level, | |
116 | + ] | |
117 | + ); | |
118 | + } | |
119 | + } | |
120 | + return $this->render( | |
121 | + 'update', | |
122 | + [ | |
123 | + 'model' => $model, | |
124 | + 'modelLangs' => $model->modelLangs, | |
125 | + 'level' => $level, | |
126 | + ] | |
127 | + ); | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * Deletes an existing TaxGroup model. | |
132 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
133 | + * | |
134 | + * @param $level integer | |
135 | + * @param integer $id | |
136 | + * | |
137 | + * @return mixed | |
138 | + */ | |
139 | + public function actionDelete($level, $id) | |
140 | + { | |
141 | + $this->findModel($id) | |
142 | + ->delete(); | |
143 | + return $this->redirect( | |
144 | + [ | |
145 | + 'index', | |
146 | + 'level' => $level, | |
147 | + ] | |
148 | + ); | |
149 | + } | |
150 | + | |
151 | + /** | |
152 | + * Finds the TaxGroup model based on its primary key value. | |
153 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
154 | + * | |
155 | + * @param integer $id | |
156 | + * | |
157 | + * @return TaxGroup the loaded model | |
158 | + * @throws NotFoundHttpException if the model cannot be found | |
159 | + */ | |
160 | + protected function findModel($id) | |
161 | + { | |
162 | + if (( $model = TaxGroup::find() | |
163 | + ->with('lang') | |
164 | + ->where([ 'id' => $id ]) | |
165 | + ->one() ) !== null | |
166 | + ) { | |
167 | + return $model; | |
168 | + } else { | |
169 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
170 | + } | |
171 | + } | |
172 | + } | ... | ... |
artbox-ecommerce/controllers/TaxOptionController.php
0 → 100755
1 | +++ a/artbox-ecommerce/controllers/TaxOptionController.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\controllers; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
6 | + use Yii; | |
7 | + use artweb\artbox\ecommerce\models\TaxOption; | |
8 | + use artweb\artbox\ecommerce\models\TaxOptionSearch; | |
9 | + use yii\db\ActiveQuery; | |
10 | + use yii\web\Controller; | |
11 | + use yii\web\NotFoundHttpException; | |
12 | + use yii\filters\VerbFilter; | |
13 | + | |
14 | + /** | |
15 | + * TaxOptionController implements the CRUD actions for TaxOption model. | |
16 | + */ | |
17 | + class TaxOptionController extends Controller | |
18 | + { | |
19 | + | |
20 | + /** | |
21 | + * @inheritdoc | |
22 | + */ | |
23 | + public function behaviors() | |
24 | + { | |
25 | + return [ | |
26 | + 'verbs' => [ | |
27 | + 'class' => VerbFilter::className(), | |
28 | + 'actions' => [ | |
29 | + 'delete' => [ 'POST' ], | |
30 | + ], | |
31 | + ], | |
32 | + ]; | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * Lists all TaxOption models. | |
37 | + * | |
38 | + * @return mixed | |
39 | + */ | |
40 | + public function actionIndex() | |
41 | + { | |
42 | + $group = $this->findGroup(Yii::$app->request->queryParams[ 'group' ]); | |
43 | + $searchModel = new TaxOptionSearch(); | |
44 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | |
45 | + /** | |
46 | + * @var ActiveQuery $query | |
47 | + */ | |
48 | + $query = $dataProvider->query; | |
49 | + $query->andWhere([ 'tax_group_id' => $group->id ]); | |
50 | + if ($group->level) { | |
51 | + $query->with('productVariants'); | |
52 | + } else { | |
53 | + $query->with('products'); | |
54 | + } | |
55 | + return $this->render( | |
56 | + 'index', | |
57 | + [ | |
58 | + 'searchModel' => $searchModel, | |
59 | + 'dataProvider' => $dataProvider, | |
60 | + 'group' => $group, | |
61 | + ] | |
62 | + ); | |
63 | + } | |
64 | + | |
65 | + /** | |
66 | + * Creates a new TaxOption model. | |
67 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
68 | + * | |
69 | + * @return mixed | |
70 | + */ | |
71 | + public function actionCreate() | |
72 | + { | |
73 | + $group = $this->findGroup(Yii::$app->request->queryParams[ 'group' ]); | |
74 | + $model = new TaxOption( | |
75 | + [ | |
76 | + 'tax_group_id' => $group->id, | |
77 | + ] | |
78 | + ); | |
79 | + $model->generateLangs(); | |
80 | + if ($model->load(Yii::$app->request->post())) { | |
81 | + $model->loadLangs(\Yii::$app->request); | |
82 | + if ($model->save() && $model->transactionStatus) { | |
83 | + return is_null(Yii::$app->request->post('create_and_new')) ? $this->redirect( | |
84 | + [ | |
85 | + 'index', | |
86 | + 'group' => $group->id, | |
87 | + ] | |
88 | + ) : $this->redirect(array_merge([ 'create' ], Yii::$app->request->queryParams)); | |
89 | + } | |
90 | + } | |
91 | + return $this->render( | |
92 | + 'create', | |
93 | + [ | |
94 | + 'model' => $model, | |
95 | + 'modelLangs' => $model->modelLangs, | |
96 | + 'group' => $group, | |
97 | + ] | |
98 | + ); | |
99 | + } | |
100 | + | |
101 | + /** | |
102 | + * Updates an existing TaxOption model. | |
103 | + * If update is successful, the browser will be redirected to the 'view' page. | |
104 | + * | |
105 | + * @param string $id | |
106 | + * | |
107 | + * @return mixed | |
108 | + */ | |
109 | + public function actionUpdate($id) | |
110 | + { | |
111 | + $model = $this->findModel($id); | |
112 | + $group = $this->findGroup($model->tax_group_id); | |
113 | + $model->generateLangs(); | |
114 | + if ($model->load(Yii::$app->request->post())) { | |
115 | + $model->loadLangs(\Yii::$app->request); | |
116 | + if ($model->save() && $model->transactionStatus) { | |
117 | + return $this->redirect( | |
118 | + [ | |
119 | + 'index', | |
120 | + 'group' => $group->id, | |
121 | + ] | |
122 | + ); | |
123 | + } | |
124 | + } | |
125 | + return $this->render( | |
126 | + 'update', | |
127 | + [ | |
128 | + 'model' => $model, | |
129 | + 'modelLangs' => $model->modelLangs, | |
130 | + 'group' => $group, | |
131 | + ] | |
132 | + ); | |
133 | + } | |
134 | + | |
135 | + /** | |
136 | + * Deletes an existing TaxOption model. | |
137 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
138 | + * | |
139 | + * @param string $id | |
140 | + * | |
141 | + * @return mixed | |
142 | + */ | |
143 | + public function actionDelete($id) | |
144 | + { | |
145 | + $model = $this->findModel($id); | |
146 | + $group_id = $model->tax_group_id; | |
147 | + | |
148 | + $model->delete(); | |
149 | + | |
150 | + return $this->redirect( | |
151 | + [ | |
152 | + 'index', | |
153 | + 'group' => $group_id, | |
154 | + ] | |
155 | + ); | |
156 | + } | |
157 | + | |
158 | + /** | |
159 | + * Finds the TaxOption model based on its primary key value. | |
160 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
161 | + * | |
162 | + * @param string $id | |
163 | + * | |
164 | + * @return TaxOption the loaded model | |
165 | + * @throws NotFoundHttpException if the model cannot be found | |
166 | + */ | |
167 | + protected function findModel($id) | |
168 | + { | |
169 | + if (( $model = TaxOption::find() | |
170 | + ->with('lang') | |
171 | + ->where([ 'id' => $id ]) | |
172 | + ->one() ) !== null | |
173 | + ) { | |
174 | + return $model; | |
175 | + } else { | |
176 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
177 | + } | |
178 | + } | |
179 | + | |
180 | + /** | |
181 | + * @param int $id | |
182 | + * | |
183 | + * @return null|TaxGroup | |
184 | + * @throws NotFoundHttpException | |
185 | + */ | |
186 | + protected function findGroup($id) | |
187 | + { | |
188 | + if (( $model = TaxGroup::find() | |
189 | + ->with('lang') | |
190 | + ->where([ 'id' => $id ]) | |
191 | + ->one() ) !== null | |
192 | + ) { | |
193 | + return $model; | |
194 | + } else { | |
195 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
196 | + } | |
197 | + } | |
198 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/controllers/VariantController.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\controllers; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\Product; | |
6 | + use artweb\artbox\ecommerce\models\ProductImage; | |
7 | + use artweb\artbox\ecommerce\models\ProductStock; | |
8 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
9 | + use artweb\artbox\ecommerce\models\ProductVariantSearch; | |
10 | + use artweb\artbox\ecommerce\models\Stock; | |
11 | + use Yii; | |
12 | + use yii\db\ActiveQuery; | |
13 | + use yii\web\Controller; | |
14 | + use yii\web\NotFoundHttpException; | |
15 | + use yii\filters\VerbFilter; | |
16 | + | |
17 | + /** | |
18 | + * VartiantController implements the CRUD actions for ProductVariant model. | |
19 | + */ | |
20 | + class VariantController extends Controller | |
21 | + { | |
22 | + | |
23 | + /** | |
24 | + * @inheritdoc | |
25 | + */ | |
26 | + public function behaviors() | |
27 | + { | |
28 | + return [ | |
29 | + 'verbs' => [ | |
30 | + 'class' => VerbFilter::className(), | |
31 | + 'actions' => [ | |
32 | + 'delete' => [ 'POST' ], | |
33 | + ], | |
34 | + ], | |
35 | + ]; | |
36 | + } | |
37 | + | |
38 | + /** | |
39 | + * Lists all ProductVariant models. | |
40 | + * | |
41 | + * @param int $product_id | |
42 | + * | |
43 | + * @return mixed | |
44 | + */ | |
45 | + public function actionIndex($product_id) | |
46 | + { | |
47 | + $product = $this->findProduct($product_id); | |
48 | + $searchModel = new ProductVariantSearch(); | |
49 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | |
50 | + /** | |
51 | + * @var ActiveQuery $query | |
52 | + */ | |
53 | + $query = $dataProvider->query; | |
54 | + $query->with('image') | |
55 | + ->andWhere([ 'product_id' => $product->id ]); | |
56 | + | |
57 | + return $this->render( | |
58 | + 'index', | |
59 | + [ | |
60 | + 'searchModel' => $searchModel, | |
61 | + 'dataProvider' => $dataProvider, | |
62 | + 'product' => $product, | |
63 | + ] | |
64 | + ); | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * Displays a single ProductVariant model. | |
69 | + * | |
70 | + * @param integer $id | |
71 | + * | |
72 | + * @return mixed | |
73 | + */ | |
74 | + public function actionView($id) | |
75 | + { | |
76 | + $model = $this->findModel($id); | |
77 | + $properties = $model->getProperties(); | |
78 | + return $this->render( | |
79 | + 'view', | |
80 | + [ | |
81 | + 'model' => $model, | |
82 | + 'properties' => $properties, | |
83 | + ] | |
84 | + ); | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * Creates a new ProductVariant model. | |
89 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
90 | + * | |
91 | + * @param int $product_id | |
92 | + * | |
93 | + * @return mixed | |
94 | + */ | |
95 | + public function actionCreate($product_id) | |
96 | + { | |
97 | + $product = $this->findProduct($product_id); | |
98 | + $model = new ProductVariant(); | |
99 | + $model->product_id = $product->id; | |
100 | + $model->generateLangs(); | |
101 | + if ($model->load(Yii::$app->request->post())) { | |
102 | + $model->loadLangs(\Yii::$app->request); | |
103 | + if ($model->save() && $model->transactionStatus) { | |
104 | + $model->stock = $this->saveStocks($model, Yii::$app->request->post('ProductStock', [])); | |
105 | + if ($model->save(true, [ 'stock' ]) && $model->transactionStatus) { | |
106 | + return $this->redirect( | |
107 | + [ | |
108 | + 'index', | |
109 | + 'product_id' => $product->id, | |
110 | + ] | |
111 | + ); | |
112 | + } | |
113 | + } | |
114 | + } | |
115 | + $groups = $model->getTaxGroupsByLevel(1); | |
116 | + return $this->render( | |
117 | + 'create', | |
118 | + [ | |
119 | + 'model' => $model, | |
120 | + 'modelLangs' => $model->modelLangs, | |
121 | + 'groups' => $groups, | |
122 | + 'stocks' => [ new ProductStock() ], | |
123 | + 'product' => $product, | |
124 | + ] | |
125 | + ); | |
126 | + } | |
127 | + | |
128 | + /** | |
129 | + * Updates an existing ProductVariant model. | |
130 | + * If update is successful, the browser will be redirected to the 'view' page. | |
131 | + * | |
132 | + * @param integer $product_id | |
133 | + * @param integer $id | |
134 | + * | |
135 | + * @return mixed | |
136 | + */ | |
137 | + public function actionUpdate($product_id, $id) | |
138 | + { | |
139 | + $product = $this->findProduct($product_id); | |
140 | + $model = $this->findModel($id); | |
141 | + $model->generateLangs(); | |
142 | + if ($model->load(Yii::$app->request->post())) { | |
143 | + $model->loadLangs(\Yii::$app->request); | |
144 | + if ($model->save() && $model->transactionStatus) { | |
145 | + $model->stock = $this->saveStocks($model, Yii::$app->request->post('ProductStock', [])); | |
146 | + if ($model->save(true, [ 'stock' ]) && $model->transactionStatus) { | |
147 | + return $this->redirect( | |
148 | + [ | |
149 | + 'index', | |
150 | + 'product_id' => $product_id, | |
151 | + ] | |
152 | + ); | |
153 | + } | |
154 | + } | |
155 | + } | |
156 | + $groups = $model->getTaxGroupsByLevel(1); | |
157 | + return $this->render( | |
158 | + 'update', | |
159 | + [ | |
160 | + 'model' => $model, | |
161 | + 'modelLangs' => $model->modelLangs, | |
162 | + 'groups' => $groups, | |
163 | + 'stocks' => ( !empty( $model->variantStocks ) ) ? $model->variantStocks : [ new ProductStock ], | |
164 | + 'product' => $product, | |
165 | + ] | |
166 | + ); | |
167 | + } | |
168 | + | |
169 | + /** | |
170 | + * Deletes an existing ProductVariant model. | |
171 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
172 | + * | |
173 | + * @param integer $product_id | |
174 | + * @param integer $id | |
175 | + * | |
176 | + * @return mixed | |
177 | + */ | |
178 | + public function actionDelete($product_id, $id) | |
179 | + { | |
180 | + | |
181 | + $this->findModel($id) | |
182 | + ->delete(); | |
183 | + | |
184 | + return $this->redirect( | |
185 | + [ | |
186 | + 'index', | |
187 | + 'product_id' => $product_id, | |
188 | + ] | |
189 | + ); | |
190 | + } | |
191 | + | |
192 | + /** | |
193 | + * Deletes an existing ProductImage model. | |
194 | + * | |
195 | + * @param $id | |
196 | + */ | |
197 | + public function actionDeleteImage($id) | |
198 | + { | |
199 | + $image = ProductImage::findOne($id); | |
200 | + | |
201 | + if ($image) { | |
202 | + $image->delete(); | |
203 | + } | |
204 | + | |
205 | + print '1'; | |
206 | + exit; | |
207 | + } | |
208 | + | |
209 | + /** | |
210 | + * Save ProductStocks for ProductVariant and return total count of products. | |
211 | + * | |
212 | + * @param \artweb\artbox\ecommerce\models\ProductVariant $productVariant | |
213 | + * @param array|null $productStocks | |
214 | + * | |
215 | + * @return int | |
216 | + */ | |
217 | + protected function saveStocks(ProductVariant $productVariant, array $productStocks = null) | |
218 | + { | |
219 | + $total_quantity = 0; | |
220 | + if (!empty( $productStocks )) { | |
221 | + $productVariant->unlinkAll('stocks', true); | |
222 | + $sorted_array = []; | |
223 | + foreach ($productStocks as $productStock) { | |
224 | + if (!empty( $productStock[ 'title' ] ) && !empty( $productStock[ 'quantity' ] )) { | |
225 | + if (!empty( $sorted_array[ $productStock[ 'title' ] ] )) { | |
226 | + $sorted_array[ $productStock[ 'title' ] ] += $productStock[ 'quantity' ]; | |
227 | + } else { | |
228 | + $sorted_array[ $productStock[ 'title' ] ] = $productStock[ 'quantity' ]; | |
229 | + } | |
230 | + } | |
231 | + } | |
232 | + $productStocks = $sorted_array; | |
233 | + $stock_names = array_keys($productStocks); | |
234 | + $stocks = Stock::find() | |
235 | + ->joinWith('lang') | |
236 | + ->where([ 'stock_lang.title' => $stock_names ]) | |
237 | + ->indexBy(function($row) { | |
238 | + /** | |
239 | + * @var Stock $row | |
240 | + */ | |
241 | + return $row->lang->title; | |
242 | + }) | |
243 | + ->all(); | |
244 | + foreach ($productStocks as $stockName => $quantity) { | |
245 | + $quantity = (int) $quantity; | |
246 | + if (!array_key_exists($stockName, $stocks)) { | |
247 | + $stock = new Stock(); | |
248 | + $stock->generateLangs(); | |
249 | + foreach ($stock->modelLangs as $modelLang) { | |
250 | + $modelLang->title = $stockName; | |
251 | + } | |
252 | + if (!$stock->save() || !$stock->transactionStatus) { | |
253 | + continue; | |
254 | + } | |
255 | + } else { | |
256 | + $stock = $stocks[ $stockName ]; | |
257 | + } | |
258 | + $psModel = new ProductStock( | |
259 | + [ | |
260 | + 'product_variant_id' => $productVariant->id, | |
261 | + 'stock_id' => $stock->id, | |
262 | + 'quantity' => $quantity, | |
263 | + ] | |
264 | + ); | |
265 | + if ($psModel->save()) { | |
266 | + $total_quantity += $quantity; | |
267 | + } | |
268 | + } | |
269 | + } else { | |
270 | + $productVariant->unlinkAll('stocks', true); | |
271 | + } | |
272 | + return $total_quantity; | |
273 | + } | |
274 | + | |
275 | + /** | |
276 | + * Finds the ProductVariant model based on its primary key value. | |
277 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
278 | + * | |
279 | + * @param integer $id | |
280 | + * | |
281 | + * @return ProductVariant the loaded model | |
282 | + * @throws NotFoundHttpException if the model cannot be found | |
283 | + */ | |
284 | + protected function findModel($id) | |
285 | + { | |
286 | + if (( $model = ProductVariant::find() | |
287 | + ->where([ 'id' => $id ]) | |
288 | + ->with('lang') | |
289 | + ->one() ) !== null | |
290 | + ) { | |
291 | + return $model; | |
292 | + } else { | |
293 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
294 | + } | |
295 | + } | |
296 | + | |
297 | + /** | |
298 | + * @param int $product_id | |
299 | + * | |
300 | + * @return Product | |
301 | + * @throws NotFoundHttpException | |
302 | + */ | |
303 | + protected function findProduct($product_id) | |
304 | + { | |
305 | + if (( $model = Product::find() | |
306 | + ->with('lang') | |
307 | + ->where([ 'id' => $product_id ]) | |
308 | + ->one() ) !== null | |
309 | + ) { | |
310 | + return $model; | |
311 | + } else { | |
312 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
313 | + } | |
314 | + } | |
315 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/helpers/FilterHelper.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\helpers; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\BrandLang; | |
6 | + use artweb\artbox\ecommerce\models\CategoryLang; | |
7 | + use artweb\artbox\ecommerce\models\Product; | |
8 | + use artweb\artbox\ecommerce\models\ProductLang; | |
9 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
10 | + use artweb\artbox\ecommerce\models\ProductVariantLang; | |
11 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
12 | + use yii\base\Object; | |
13 | + use yii\db\ActiveQuery; | |
14 | + use yii\db\Query; | |
15 | + use yii\helpers\ArrayHelper; | |
16 | + | |
17 | + class FilterHelper extends Object | |
18 | + { | |
19 | + | |
20 | + public static $optionsList = []; | |
21 | + | |
22 | + /** | |
23 | + * Get TaxGroups | |
24 | + * | |
25 | + * @return array | |
26 | + */ | |
27 | + public static function optionsTemplate() | |
28 | + { | |
29 | + if (empty( static::$optionsList )) { | |
30 | + return static::$optionsList = ArrayHelper::getColumn( | |
31 | + TaxGroup::find() | |
32 | + ->joinWith('lang') | |
33 | + ->where([ 'is_filter' => 'TRUE' ]) | |
34 | + ->all(), | |
35 | + 'lang.alias' | |
36 | + ); | |
37 | + } else { | |
38 | + return static::$optionsList; | |
39 | + } | |
40 | + | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * Return custom filter-option link | |
45 | + * | |
46 | + * @param array $filter | |
47 | + * @param string $key | |
48 | + * @param mixed $value | |
49 | + * @param bool $remove | |
50 | + * | |
51 | + * @return array | |
52 | + */ | |
53 | + public static function getFilterForOption(array $filter, string $key, $value, bool $remove = false) | |
54 | + { | |
55 | + | |
56 | + $optionsTemplate = self::optionsTemplate(); | |
57 | + array_unshift($optionsTemplate, "special", "brands"); | |
58 | + | |
59 | + $result = $filter; | |
60 | + | |
61 | + if (is_array($value)) { | |
62 | + foreach ($value as $value_key => $value_items) { | |
63 | + if (!is_array($value_items)) { | |
64 | + $value_items = [ $value_items ]; | |
65 | + } | |
66 | + foreach ($value_items as $value_item) { | |
67 | + if ($remove && isset( $result[ $key ] ) && ( $i = array_search( | |
68 | + $value_item, | |
69 | + $result[ $key ][ $value_key ] | |
70 | + ) ) !== false | |
71 | + ) { | |
72 | + unset( $result[ $key ][ $value_key ][ $i ] ); | |
73 | + if (empty( $result[ $key ][ $value_key ] )) { | |
74 | + unset( $result[ $key ][ $value_key ] ); | |
75 | + } | |
76 | + } else { | |
77 | + if (!isset( $result[ $key ][ $value_key ] ) || array_search( | |
78 | + $value_item, | |
79 | + $result[ $key ][ $value_key ] | |
80 | + ) === false | |
81 | + ) { | |
82 | + $result[ $key ][ $value_key ][] = $value_item; | |
83 | + } | |
84 | + } | |
85 | + } | |
86 | + } | |
87 | + } else { | |
88 | + if ($remove && isset( $result[ $key ] ) && ( $i = array_search($value, $result[ $key ]) ) !== false) { | |
89 | + unset( $result[ $key ][ $i ] ); | |
90 | + if (empty( $result[ $key ] )) { | |
91 | + unset( $result[ $key ] ); | |
92 | + } | |
93 | + } else { | |
94 | + if (!isset( $result[ $key ] ) || array_search($value, $result[ $key ]) === false) { | |
95 | + $result[ $key ][] = $value; | |
96 | + } | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + $filterView = []; | |
101 | + | |
102 | + foreach ($optionsTemplate as $optionKey) { | |
103 | + if (isset( $result[ $optionKey ] )) { | |
104 | + $filterView[ $optionKey ] = $result[ $optionKey ]; | |
105 | + } | |
106 | + | |
107 | + } | |
108 | + | |
109 | + return $filterView; | |
110 | + } | |
111 | + | |
112 | + /** | |
113 | + * Fill query with filter conditions | |
114 | + * | |
115 | + * @param ActiveQuery $query | |
116 | + * @param array $params | |
117 | + */ | |
118 | + public static function setQueryParams(ActiveQuery $query, array $params) | |
119 | + { | |
120 | + $last_query = null; | |
121 | + foreach ($params as $key => $param) { | |
122 | + switch ($key) { | |
123 | + case 'special': | |
124 | + self::filterSpecial($param, $query); | |
125 | + break; | |
126 | + case 'brands': | |
127 | + self::filterBrands($param, $query); | |
128 | + break; | |
129 | + case 'keywords': | |
130 | + self::filterKeywords($param, $query); | |
131 | + break; | |
132 | + case 'prices': | |
133 | + self::filterPrices($param, $query); | |
134 | + break; | |
135 | + default: | |
136 | + $last_query = self::filterOptions($param, $last_query); | |
137 | + break; | |
138 | + } | |
139 | + } | |
140 | + // If tax option filters were provided filter query with them | |
141 | + if (!empty( $last_query )) { | |
142 | + $query->andWhere([ 'product.id' => $last_query ]); | |
143 | + } | |
144 | + } | |
145 | + | |
146 | + /** | |
147 | + * Tax Option filter | |
148 | + * | |
149 | + * @param string[] $params | |
150 | + * @param \yii\db\Query|null $last_query | |
151 | + * | |
152 | + * @return Query | |
153 | + */ | |
154 | + private static function filterOptions(array $params, Query $last_query = null): Query | |
155 | + { | |
156 | + $variant_query = ( new Query() )->distinct() | |
157 | + ->select('product_variant.product_id as products') | |
158 | + ->from('product_variant_option') | |
159 | + ->innerJoin( | |
160 | + 'product_variant', | |
161 | + 'product_variant_option.product_variant_id = product_variant.id' | |
162 | + ) | |
163 | + ->innerJoin( | |
164 | + 'tax_option', | |
165 | + 'tax_option.id = product_variant_option.option_id' | |
166 | + ) | |
167 | + ->innerJoin( | |
168 | + 'tax_option_lang', | |
169 | + 'tax_option_lang.tax_option_id = tax_option.id' | |
170 | + ) | |
171 | + ->where([ 'tax_option_lang.alias' => $params ]); | |
172 | + $product_query = ( new Query() )->distinct() | |
173 | + ->select('product_option.product_id as products') | |
174 | + ->from('product_option') | |
175 | + ->innerJoin('tax_option', 'product_option.option_id = tax_option.id') | |
176 | + ->innerJoin( | |
177 | + 'tax_option_lang', | |
178 | + 'tax_option_lang.tax_option_id = tax_option.id' | |
179 | + ) | |
180 | + ->where( | |
181 | + [ 'tax_option_lang.alias' => $params ] | |
182 | + ) | |
183 | + ->union($variant_query); | |
184 | + $query = ( new Query() )->select('products') | |
185 | + ->from([ 'result_table' => $product_query ]); | |
186 | + if (!empty( $last_query )) { | |
187 | + $query->andWhere([ 'product.id' => $last_query ]); | |
188 | + } | |
189 | + return $query; | |
190 | + } | |
191 | + | |
192 | + /** | |
193 | + * Fill $query with special filters (used in Product) | |
194 | + * | |
195 | + * @param array $params | |
196 | + * @param \yii\db\ActiveQuery $query | |
197 | + */ | |
198 | + private static function filterSpecial(array $params, ActiveQuery $query) | |
199 | + { | |
200 | + $conditions = []; | |
201 | + /** | |
202 | + * @var string $key | |
203 | + */ | |
204 | + foreach ($params as $key => $param) { | |
205 | + $conditions[] = [ | |
206 | + '=', | |
207 | + Product::tableName() . '.' . $key, | |
208 | + $param, | |
209 | + ]; | |
210 | + } | |
211 | + /* If 2 or more special conditions get all that satisfy at least one of them. */ | |
212 | + if (count($conditions) > 1) { | |
213 | + array_unshift($conditions, 'or'); | |
214 | + } else { | |
215 | + $conditions = $conditions[ 0 ]; | |
216 | + } | |
217 | + $query->andFilterWhere($conditions); | |
218 | + } | |
219 | + | |
220 | + /** | |
221 | + * Fill query with brands filter | |
222 | + * | |
223 | + * @param int[] $param | |
224 | + * @param \yii\db\ActiveQuery $query | |
225 | + */ | |
226 | + private static function filterBrands(array $param, ActiveQuery $query) | |
227 | + { | |
228 | + $query->andFilterWhere([ Product::tableName() . '.brand_id' => $param ]); | |
229 | + } | |
230 | + | |
231 | + /** | |
232 | + * Fill query with keywords filter | |
233 | + * | |
234 | + * @param array $params | |
235 | + * @param \yii\db\ActiveQuery $query | |
236 | + */ | |
237 | + private static function filterKeywords(array $params, ActiveQuery $query) | |
238 | + { | |
239 | + $conditions = []; | |
240 | + if (!empty( $params )) { | |
241 | + if (!is_array($params)) { | |
242 | + $params = [ $params ]; | |
243 | + } | |
244 | + /** | |
245 | + * @var string $param Inputed keyword | |
246 | + */ | |
247 | + foreach ($params as $param) { | |
248 | + $conditions[] = [ | |
249 | + 'or', | |
250 | + [ | |
251 | + 'ilike', | |
252 | + ProductLang::tableName() . '.title', | |
253 | + $param, | |
254 | + ], | |
255 | + [ | |
256 | + 'ilike', | |
257 | + BrandLang::tableName() . '.title', | |
258 | + $param, | |
259 | + ], | |
260 | + [ | |
261 | + 'ilike', | |
262 | + CategoryLang::tableName() . '.title', | |
263 | + $param, | |
264 | + ], | |
265 | + [ | |
266 | + 'ilike', | |
267 | + ProductVariantLang::tableName() . '.title', | |
268 | + $param, | |
269 | + ], | |
270 | + ]; | |
271 | + } | |
272 | + } | |
273 | + if (count($conditions) > 1) { | |
274 | + array_unshift($conditions, 'or'); | |
275 | + } else { | |
276 | + $conditions = $conditions[ 0 ]; | |
277 | + } | |
278 | + $query->andFilterWhere($conditions); | |
279 | + } | |
280 | + | |
281 | + /** | |
282 | + * Fill query with price limits filter | |
283 | + * | |
284 | + * @param array $params | |
285 | + * @param \yii\db\ActiveQuery $query | |
286 | + */ | |
287 | + private static function filterPrices(array $params, ActiveQuery $query) | |
288 | + { | |
289 | + $conditions = []; | |
290 | + if (!empty( $params[ 'min' ] ) && $params[ 'min' ] > 0) { | |
291 | + $conditions[] = [ | |
292 | + '>=', | |
293 | + ProductVariant::tableName() . '.price', | |
294 | + $params[ 'min' ], | |
295 | + ]; | |
296 | + } | |
297 | + if (!empty( $params[ 'max' ] ) && $params[ 'max' ] > 0) { | |
298 | + $conditions[] = [ | |
299 | + '<=', | |
300 | + ProductVariant::tableName() . '.price', | |
301 | + $params[ 'max' ], | |
302 | + ]; | |
303 | + } | |
304 | + if (count($conditions) > 1) { | |
305 | + array_unshift($conditions, 'and'); | |
306 | + } else { | |
307 | + $conditions = $conditions[ 0 ]; | |
308 | + } | |
309 | + $query->andFilterWhere($conditions); | |
310 | + } | |
311 | + | |
312 | + } | |
313 | + | |
0 | 314 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/helpers/ProductHelper.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\helpers; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\Category; | |
6 | + use artweb\artbox\ecommerce\models\Product; | |
7 | + use yii\base\Object; | |
8 | + use Yii; | |
9 | + use yii\db\ActiveQuery; | |
10 | + use yii\helpers\ArrayHelper; | |
11 | + | |
12 | + class ProductHelper extends Object | |
13 | + { | |
14 | + | |
15 | + /** | |
16 | + * @todo ArtboxTree | |
17 | + * @return array | |
18 | + */ | |
19 | + public static function getCategories() | |
20 | + { | |
21 | + return Category::find() | |
22 | + ->getTree(null, 'lang'); | |
23 | + } | |
24 | + | |
25 | + /** | |
26 | + * Add $product_id to last products in session. Limit 16 products. | |
27 | + * | |
28 | + * @param int $product_id | |
29 | + */ | |
30 | + public static function addLastProducts(int $product_id) | |
31 | + { | |
32 | + $last_products = self::getLastProducts(); | |
33 | + if (!in_array($product_id, $last_products)) { | |
34 | + $last_products[] = intval($product_id); | |
35 | + if (count($last_products) > 16) { | |
36 | + array_shift($last_products); | |
37 | + } | |
38 | + Yii::$app->session->set('last_products', $last_products); | |
39 | + } | |
40 | + } | |
41 | + | |
42 | + /** | |
43 | + * Get last products ids from session or last Product models with ProductVariant, which are in stock if | |
44 | + * $as_object is true | |
45 | + * | |
46 | + * @param bool $as_object | |
47 | + * | |
48 | + * @return array | |
49 | + */ | |
50 | + public static function getLastProducts(bool $as_object = false) | |
51 | + { | |
52 | + $last_products = Yii::$app->session->get('last_products', []); | |
53 | + if ($as_object) { | |
54 | + $last_products = Product::find() | |
55 | + ->joinWith([ 'variant' ]) | |
56 | + ->where([ 'product.id' => $last_products ]) | |
57 | + ->andWhere( | |
58 | + [ | |
59 | + '!=', | |
60 | + 'product_variant.stock', | |
61 | + 0, | |
62 | + ] | |
63 | + ) | |
64 | + ->indexBy('id') | |
65 | + ->all(); | |
66 | + } | |
67 | + return array_reverse($last_products); | |
68 | + } | |
69 | + | |
70 | + /** | |
71 | + * Get special Products array with ProductVariants, which are in stock | |
72 | + * Available types: | |
73 | + * * top | |
74 | + * * new | |
75 | + * * promo | |
76 | + * | |
77 | + * @param string $type | |
78 | + * @param int $count | |
79 | + * | |
80 | + * @return Product[] | |
81 | + */ | |
82 | + public static function getSpecialProducts(string $type, int $count) | |
83 | + { | |
84 | + switch ($type) { | |
85 | + case 'top': | |
86 | + $data = [ 'is_top' => true ]; | |
87 | + break; | |
88 | + case 'new': | |
89 | + $data = [ 'is_new' => true ]; | |
90 | + break; | |
91 | + case 'promo': | |
92 | + $data = [ 'is_discount' => true ]; | |
93 | + break; | |
94 | + default: | |
95 | + return []; | |
96 | + break; | |
97 | + } | |
98 | + return Product::find() | |
99 | + ->with('lang') | |
100 | + ->joinWith('variants.lang') | |
101 | + ->where($data) | |
102 | + ->andWhere( | |
103 | + [ | |
104 | + '!=', | |
105 | + 'productVariant.stock', | |
106 | + 0, | |
107 | + ] | |
108 | + ) | |
109 | + ->limit($count) | |
110 | + ->all(); | |
111 | + } | |
112 | + | |
113 | + /** | |
114 | + * Get ActiveQuery to get similar products to $product | |
115 | + * | |
116 | + * @param Product $product | |
117 | + * @param int $count | |
118 | + * | |
119 | + * @return ActiveQuery | |
120 | + */ | |
121 | + public static function getSimilarProducts(Product $product, $count = 10): ActiveQuery | |
122 | + { | |
123 | + $query = Product::find(); | |
124 | + if (empty( $product->properties )) { | |
125 | + $query->where('0 = 1'); | |
126 | + return $query; | |
127 | + } | |
128 | + $query->innerJoinWith('variants') | |
129 | + ->joinWith('categories') | |
130 | + ->where( | |
131 | + [ | |
132 | + '!=', | |
133 | + 'product_variant.stock', | |
134 | + 0, | |
135 | + ] | |
136 | + ) | |
137 | + ->andWhere( | |
138 | + [ 'product_category.category_id' => ArrayHelper::getColumn($product->categories, 'id') ] | |
139 | + ); | |
140 | + $options = []; | |
141 | + foreach ($product->properties as $group) { | |
142 | + foreach ($group->options as $option) { | |
143 | + $options[] = $option->id; | |
144 | + } | |
145 | + } | |
146 | + if (!empty( $options )) { | |
147 | + $query->innerJoinWith('options') | |
148 | + ->andWhere([ 'product_option.option_id' => $options ]); | |
149 | + } else { | |
150 | + $query->where('0 = 1'); | |
151 | + return $query; | |
152 | + } | |
153 | + $query->andWhere( | |
154 | + [ | |
155 | + '!=', | |
156 | + 'product.id', | |
157 | + $product->id, | |
158 | + ] | |
159 | + ); | |
160 | + $query->groupBy('product.id'); | |
161 | + $query->limit($count); | |
162 | + return $query; | |
163 | + } | |
164 | + | |
165 | + /** | |
166 | + * Add last category id to session | |
167 | + * | |
168 | + * @param int $category_id | |
169 | + */ | |
170 | + public static function addLastCategory(int $category_id) | |
171 | + { | |
172 | + \Yii::$app->session->set('last_category_id', $category_id); | |
173 | + } | |
174 | + | |
175 | + /** | |
176 | + * Get last category id from session | |
177 | + * | |
178 | + * @return int | |
179 | + */ | |
180 | + public static function getLastCategory(): int | |
181 | + { | |
182 | + return \Yii::$app->session->get('last_category_id'); | |
183 | + } | |
184 | + } | |
0 | 185 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/models/Brand.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\SaveImgBehavior; | |
6 | + use common\modules\language\behaviors\LanguageBehavior; | |
7 | + use Yii; | |
8 | + use yii\db\ActiveQuery; | |
9 | + use yii\db\ActiveRecord; | |
10 | + use yii\web\Request; | |
11 | + | |
12 | + /** | |
13 | + * This is the model class for table "brand". | |
14 | + * | |
15 | + * @property integer $id | |
16 | + * @property string $image | |
17 | + * @property bool $in_menu | |
18 | + * @property Product[] $products | |
19 | + * @property string $remote_id | |
20 | + * * From language behavior * | |
21 | + * @property BrandLang $lang | |
22 | + * @property BrandLang[] $langs | |
23 | + * @property BrandLang $objectLang | |
24 | + * @property string $ownerKey | |
25 | + * @property string $langKey | |
26 | + * @property BrandLang[] $modelLangs | |
27 | + * @property bool $transactionStatus | |
28 | + * @method string getOwnerKey() | |
29 | + * @method void setOwnerKey( string $value ) | |
30 | + * @method string getLangKey() | |
31 | + * @method void setLangKey( string $value ) | |
32 | + * @method ActiveQuery getLangs() | |
33 | + * @method ActiveQuery getLang( integer $language_id ) | |
34 | + * @method BrandLang[] generateLangs() | |
35 | + * @method void loadLangs( Request $request ) | |
36 | + * @method bool linkLangs() | |
37 | + * @method bool saveLangs() | |
38 | + * @method bool getTransactionStatus() | |
39 | + * * End language behavior * | |
40 | + * * From SaveImgBehavior | |
41 | + * @property string|null $imageFile | |
42 | + * @property string|null $imageUrl | |
43 | + * @method string|null getImageFile( int $field ) | |
44 | + * @method string|null getImageUrl( int $field ) | |
45 | + * * End SaveImgBehavior | |
46 | + */ | |
47 | + class Brand extends ActiveRecord | |
48 | + { | |
49 | + /** | |
50 | + * @inheritdoc | |
51 | + */ | |
52 | + public static function tableName() | |
53 | + { | |
54 | + return 'brand'; | |
55 | + } | |
56 | + | |
57 | + public function behaviors() | |
58 | + { | |
59 | + return [ | |
60 | + [ | |
61 | + 'class' => SaveImgBehavior::className(), | |
62 | + 'fields' => [ | |
63 | + [ | |
64 | + 'name' => 'image', | |
65 | + 'directory' => 'brand', | |
66 | + ], | |
67 | + ], | |
68 | + ], | |
69 | + 'language' => [ | |
70 | + 'class' => LanguageBehavior::className(), | |
71 | + ], | |
72 | + ]; | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * @inheritdoc | |
77 | + */ | |
78 | + public function rules() | |
79 | + { | |
80 | + return [ | |
81 | + [ | |
82 | + [ 'in_menu' ], | |
83 | + 'boolean', | |
84 | + ], | |
85 | + ]; | |
86 | + } | |
87 | + | |
88 | + /** | |
89 | + * @inheritdoc | |
90 | + */ | |
91 | + public function attributeLabels() | |
92 | + { | |
93 | + return [ | |
94 | + 'id' => Yii::t('product', 'Brand ID'), | |
95 | + 'image' => Yii::t('product', 'Image'), | |
96 | + ]; | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * Get all products with current brand | |
101 | + * | |
102 | + * @return \yii\db\ActiveQuery | |
103 | + */ | |
104 | + public function getProducts() | |
105 | + { | |
106 | + return $this->hasMany(Product::className(), [ 'brand_id' => 'id' ]); | |
107 | + } | |
108 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/BrandLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "brand_lang". | |
11 | + * | |
12 | + * @property integer $brand_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $title | |
15 | + * @property string $meta_title | |
16 | + * @property string $meta_robots | |
17 | + * @property string $meta_description | |
18 | + * @property string $seo_text | |
19 | + * @property string $alias | |
20 | + * @property Brand $brand | |
21 | + * @property Language $language | |
22 | + */ | |
23 | + class BrandLang extends ActiveRecord | |
24 | + { | |
25 | + | |
26 | + public static function primaryKey() | |
27 | + { | |
28 | + return [ | |
29 | + 'brand_id', | |
30 | + 'language_id', | |
31 | + ]; | |
32 | + } | |
33 | + | |
34 | + /** | |
35 | + * @inheritdoc | |
36 | + */ | |
37 | + public static function tableName() | |
38 | + { | |
39 | + return 'brand_lang'; | |
40 | + } | |
41 | + | |
42 | + public function behaviors() | |
43 | + { | |
44 | + return [ | |
45 | + 'slug' => [ | |
46 | + 'class' => 'common\behaviors\Slug', | |
47 | + ], | |
48 | + ]; | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * @inheritdoc | |
53 | + */ | |
54 | + public function rules() | |
55 | + { | |
56 | + return [ | |
57 | + [ | |
58 | + [ 'title' ], | |
59 | + 'required', | |
60 | + ], | |
61 | + [ | |
62 | + [ 'seo_text' ], | |
63 | + 'string', | |
64 | + ], | |
65 | + [ | |
66 | + [ | |
67 | + 'title', | |
68 | + 'meta_title', | |
69 | + 'meta_robots', | |
70 | + 'meta_description', | |
71 | + 'alias', | |
72 | + ], | |
73 | + 'string', | |
74 | + 'max' => 255, | |
75 | + ], | |
76 | + [ | |
77 | + [ | |
78 | + 'brand_id', | |
79 | + 'language_id', | |
80 | + ], | |
81 | + 'unique', | |
82 | + 'targetAttribute' => [ | |
83 | + 'brand_id', | |
84 | + 'language_id', | |
85 | + ], | |
86 | + 'message' => 'The combination of Brand ID and Language ID has already been taken.', | |
87 | + ], | |
88 | + [ | |
89 | + [ 'brand_id' ], | |
90 | + 'exist', | |
91 | + 'skipOnError' => true, | |
92 | + 'targetClass' => Brand::className(), | |
93 | + 'targetAttribute' => [ 'brand_id' => 'id' ], | |
94 | + ], | |
95 | + [ | |
96 | + [ 'language_id' ], | |
97 | + 'exist', | |
98 | + 'skipOnError' => true, | |
99 | + 'targetClass' => Language::className(), | |
100 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
101 | + ], | |
102 | + ]; | |
103 | + } | |
104 | + | |
105 | + /** | |
106 | + * @inheritdoc | |
107 | + */ | |
108 | + public function attributeLabels() | |
109 | + { | |
110 | + return [ | |
111 | + 'brand_id' => Yii::t('app', 'Brand ID'), | |
112 | + 'language_id' => Yii::t('app', 'Language ID'), | |
113 | + 'title' => Yii::t('app', 'Name'), | |
114 | + 'meta_title' => Yii::t('app', 'Meta Title'), | |
115 | + 'meta_robots' => Yii::t('app', 'Meta Robots'), | |
116 | + 'meta_description' => Yii::t('app', 'Meta Desc'), | |
117 | + 'seo_text' => Yii::t('app', 'Seo Text'), | |
118 | + 'alias' => Yii::t('app', 'Alias'), | |
119 | + ]; | |
120 | + } | |
121 | + | |
122 | + /** | |
123 | + * @return \yii\db\ActiveQuery | |
124 | + */ | |
125 | + public function getBrand() | |
126 | + { | |
127 | + return $this->hasOne(Brand::className(), [ 'id' => 'brand_id' ]); | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * @return \yii\db\ActiveQuery | |
132 | + */ | |
133 | + public function getLanguage() | |
134 | + { | |
135 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
136 | + } | |
137 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/BrandSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * BrandSearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\Brand`. | |
11 | + */ | |
12 | + class BrandSearch extends Brand | |
13 | + { | |
14 | + | |
15 | + public $brandName; | |
16 | + | |
17 | + /** | |
18 | + * @inheritdoc | |
19 | + */ | |
20 | + public function rules() | |
21 | + { | |
22 | + return [ | |
23 | + [ | |
24 | + [ 'brandName' ], | |
25 | + 'safe', | |
26 | + ], | |
27 | + [ | |
28 | + [ 'id' ], | |
29 | + 'integer', | |
30 | + ], | |
31 | + ]; | |
32 | + } | |
33 | + | |
34 | + public function behaviors() | |
35 | + { | |
36 | + return []; | |
37 | + } | |
38 | + | |
39 | + /** | |
40 | + * @inheritdoc | |
41 | + */ | |
42 | + public function scenarios() | |
43 | + { | |
44 | + // bypass scenarios() implementation in the parent class | |
45 | + return Model::scenarios(); | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * Creates data provider instance with search query applied | |
50 | + * | |
51 | + * @param array $params | |
52 | + * | |
53 | + * @return ActiveDataProvider | |
54 | + */ | |
55 | + public function search($params) | |
56 | + { | |
57 | + $query = Brand::find() | |
58 | + ->joinWith('lang'); | |
59 | + | |
60 | + // add conditions that should always apply here | |
61 | + | |
62 | + $dataProvider = new ActiveDataProvider( | |
63 | + [ | |
64 | + 'query' => $query, | |
65 | + ] | |
66 | + ); | |
67 | + | |
68 | + $this->load($params); | |
69 | + | |
70 | + /*if (!$this->validate()) { | |
71 | + // uncomment the following line if you do not want to return any records when validation fails | |
72 | + // $query->where('0=1'); | |
73 | + return $dataProvider; | |
74 | + }*/ | |
75 | + | |
76 | + $dataProvider->setSort( | |
77 | + [ | |
78 | + 'attributes' => [ | |
79 | + 'id', | |
80 | + 'brandName' => [ | |
81 | + 'asc' => [ 'brand_lang.title' => SORT_ASC ], | |
82 | + 'desc' => [ 'brand_lang.title' => SORT_DESC ], | |
83 | + ], | |
84 | + ], | |
85 | + ] | |
86 | + ); | |
87 | + | |
88 | + // grid filtering conditions | |
89 | + $query->andFilterWhere( | |
90 | + [ | |
91 | + 'brand.id' => $this->id, | |
92 | + ] | |
93 | + ) | |
94 | + ->andFilterWhere( | |
95 | + [ | |
96 | + 'ilike', | |
97 | + 'brand_lang.title', | |
98 | + $this->brandName, | |
99 | + ] | |
100 | + ); | |
101 | + | |
102 | + return $dataProvider; | |
103 | + } | |
104 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/Category.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\SaveImgBehavior; | |
6 | + use common\components\artboxtree\ArtboxTreeBehavior; | |
7 | + use common\modules\language\behaviors\LanguageBehavior; | |
8 | + use common\modules\language\models\Language; | |
9 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
10 | + use Yii; | |
11 | + use yii\base\InvalidParamException; | |
12 | + use yii\db\ActiveQuery; | |
13 | + use yii\db\ActiveRecord; | |
14 | + use yii\db\Query; | |
15 | + use yii\web\Request; | |
16 | + | |
17 | + /** | |
18 | + * This is the model class for table "category". | |
19 | + * | |
20 | + * @todo Write doc for ArtboxTreeBehavior | |
21 | + * @property integer $id | |
22 | + * @property integer $remote_id | |
23 | + * @property integer $parent_id | |
24 | + * @property string $path | |
25 | + * @property integer $depth | |
26 | + * @property string $image | |
27 | + * @property integer $product_unit_id | |
28 | + * @property Product[] $products | |
29 | + * @property ProductUnit $productUnit | |
30 | + * @property ProductCategory[] $productCategories | |
31 | + * @property Brand[] $brands | |
32 | + * @property TaxGroup[] $taxGroups | |
33 | + * * From language behavior * | |
34 | + * @property CategoryLang $lang | |
35 | + * @property CategoryLang[] $langs | |
36 | + * @property CategoryLang $objectLang | |
37 | + * @property string $ownerKey | |
38 | + * @property string $langKey | |
39 | + * @property CategoryLang[] $modelLangs | |
40 | + * @property bool $transactionStatus | |
41 | + * @method string getOwnerKey() | |
42 | + * @method void setOwnerKey( string $value ) | |
43 | + * @method string getLangKey() | |
44 | + * @method void setLangKey( string $value ) | |
45 | + * @method ActiveQuery getLangs() | |
46 | + * @method ActiveQuery getLang( integer $language_id ) | |
47 | + * @method CategoryLang[] generateLangs() | |
48 | + * @method void loadLangs( Request $request ) | |
49 | + * @method bool linkLangs() | |
50 | + * @method bool saveLangs() | |
51 | + * @method bool getTransactionStatus() | |
52 | + * * End language behavior * | |
53 | + * * From SaveImgBehavior | |
54 | + * @property string|null $imageFile | |
55 | + * @property string|null $imageUrl | |
56 | + * @method string|null getImageFile( int $field ) | |
57 | + * @method string|null getImageUrl( int $field ) | |
58 | + * * End SaveImgBehavior | |
59 | + */ | |
60 | + class Category extends ActiveRecord | |
61 | + { | |
62 | + | |
63 | + public function behaviors() | |
64 | + { | |
65 | + return [ | |
66 | + 'artboxtree' => [ | |
67 | + 'class' => ArtboxTreeBehavior::className(), | |
68 | + 'keyNameGroup' => null, | |
69 | + 'keyNamePath' => 'path', | |
70 | + ], | |
71 | + 'language' => [ | |
72 | + 'class' => LanguageBehavior::className(), | |
73 | + ], | |
74 | + [ | |
75 | + 'class' => SaveImgBehavior::className(), | |
76 | + 'fields' => [ | |
77 | + [ | |
78 | + 'name' => 'image', | |
79 | + 'directory' => 'categories', | |
80 | + ], | |
81 | + ], | |
82 | + ], | |
83 | + ]; | |
84 | + } | |
85 | + | |
86 | + /** | |
87 | + * @inheritdoc | |
88 | + */ | |
89 | + public static function tableName() | |
90 | + { | |
91 | + return 'category'; | |
92 | + } | |
93 | + | |
94 | + /** | |
95 | + * @inheritdoc | |
96 | + */ | |
97 | + public function rules() | |
98 | + { | |
99 | + return [ | |
100 | + [ | |
101 | + [ | |
102 | + 'parent_id', | |
103 | + 'depth', | |
104 | + 'product_unit_id', | |
105 | + ], | |
106 | + 'integer', | |
107 | + ], | |
108 | + [ | |
109 | + [ | |
110 | + 'path', | |
111 | + ], | |
112 | + 'string', | |
113 | + ], | |
114 | + ]; | |
115 | + } | |
116 | + | |
117 | + /** | |
118 | + * @inheritdoc | |
119 | + */ | |
120 | + public function attributeLabels() | |
121 | + { | |
122 | + return [ | |
123 | + 'id' => Yii::t('product', 'Category ID'), | |
124 | + 'parent_id' => Yii::t('product', 'Parent ID'), | |
125 | + 'path' => Yii::t('product', 'Path'), | |
126 | + 'depth' => Yii::t('product', 'Depth'), | |
127 | + 'image' => Yii::t('product', 'Image'), | |
128 | + 'imageUrl' => Yii::t('product', 'Image'), | |
129 | + 'product_unit_id' => Yii::t('product', 'Product Unit ID'), | |
130 | + 'remote_id' => Yii::t('product', 'Remote ID'), | |
131 | + ]; | |
132 | + } | |
133 | + | |
134 | + public static function find() | |
135 | + { | |
136 | + return new CategoryQuery(get_called_class()); | |
137 | + } | |
138 | + | |
139 | + /** | |
140 | + * @return \yii\db\ActiveQuery | |
141 | + */ | |
142 | + public function getProductUnit() | |
143 | + { | |
144 | + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]); | |
145 | + } | |
146 | + | |
147 | + /** | |
148 | + * @return ActiveQuery | |
149 | + */ | |
150 | + public function getProducts() | |
151 | + { | |
152 | + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ]) | |
153 | + ->viaTable('product_category', [ 'category_id' => 'id' ]); | |
154 | + } | |
155 | + | |
156 | + /** | |
157 | + * @return \yii\db\ActiveQuery | |
158 | + */ | |
159 | + public function getProductCategories() | |
160 | + { | |
161 | + return $this->hasMany(ProductCategory::className(), [ 'category_id' => 'id' ]); | |
162 | + } | |
163 | + | |
164 | + /** | |
165 | + * Get all brands for Category query | |
166 | + * | |
167 | + * @return ActiveQuery | |
168 | + */ | |
169 | + public function getBrands() | |
170 | + { | |
171 | + return $this->hasMany(Brand::className(), [ 'id' => 'brand_id' ]) | |
172 | + ->via('products'); | |
173 | + } | |
174 | + | |
175 | + /** | |
176 | + * Get Tax Groups by level | |
177 | + * * 0 for Product | |
178 | + * * 1 for ProductVariant | |
179 | + * | |
180 | + * @param int $level | |
181 | + * | |
182 | + * @return ActiveQuery | |
183 | + */ | |
184 | + public function getTaxGroupsByLevel(int $level) | |
185 | + { | |
186 | + if ($level !== 0 || $level !== 1) { | |
187 | + throw new InvalidParamException('Level supports only 0 and 1 values'); | |
188 | + } | |
189 | + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) | |
190 | + ->viaTable('tax_group_to_category', [ 'category_id' => 'id' ]) | |
191 | + ->andWhere([ 'level' => $level ]); | |
192 | + } | |
193 | + | |
194 | + /** | |
195 | + * Леша найди путь как убрать это, мб в базу записать просто по умолчанию значение и notnull | |
196 | + * | |
197 | + * @param bool $insert | |
198 | + * | |
199 | + * @return bool | |
200 | + */ | |
201 | + public function beforeSave($insert) | |
202 | + { | |
203 | + if (parent::beforeSave($insert)) { | |
204 | + | |
205 | + if (empty( $this->parent_id )) { | |
206 | + $this->parent_id = 0; | |
207 | + } | |
208 | + | |
209 | + return true; | |
210 | + } | |
211 | + return false; | |
212 | + } | |
213 | + | |
214 | + /** | |
215 | + * Get query for activefilter for current category | |
216 | + * | |
217 | + * @return Query | |
218 | + */ | |
219 | + public function getActiveFilters() | |
220 | + { | |
221 | + $language_id = Language::getCurrent()->id; | |
222 | + $query1 = ( new Query() )->distinct() | |
223 | + ->select( | |
224 | + [ | |
225 | + 'option_id', | |
226 | + ] | |
227 | + ) | |
228 | + ->from('tax_option') | |
229 | + ->innerJoin( | |
230 | + 'product_variant_option', | |
231 | + 'tax_option.id = product_variant_option.option_id' | |
232 | + ) | |
233 | + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id') | |
234 | + ->innerJoin( | |
235 | + 'product_variant', | |
236 | + 'product_variant.id = product_variant_option.product_variant_id' | |
237 | + ) | |
238 | + ->innerJoin('product', 'product.id = product_variant.product_id') | |
239 | + ->innerJoin('product_category', 'product_category.product_id = product.id') | |
240 | + ->where( | |
241 | + [ | |
242 | + 'product_category.category_id' => $this->id, | |
243 | + 'tax_group.is_filter' => true, | |
244 | + ] | |
245 | + ) | |
246 | + ->andWhere( | |
247 | + [ | |
248 | + '!=', | |
249 | + 'product_variant.stock', | |
250 | + 0, | |
251 | + ] | |
252 | + ); | |
253 | + | |
254 | + $query2 = ( new Query() )->distinct() | |
255 | + ->select( | |
256 | + [ | |
257 | + 'option_id', | |
258 | + ] | |
259 | + ) | |
260 | + ->from('tax_option') | |
261 | + ->innerJoin( | |
262 | + 'product_option', | |
263 | + 'tax_option.id = product_option.option_id' | |
264 | + ) | |
265 | + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id') | |
266 | + ->innerJoin('product', 'product.id = product_option.product_id') | |
267 | + ->innerJoin('product_category', 'product_category.product_id = product.id') | |
268 | + ->innerJoin('product_variant', 'product_variant.product_id = product.id') | |
269 | + ->where( | |
270 | + [ | |
271 | + 'product_category.category_id' => $this->id, | |
272 | + 'tax_group.is_filter' => true, | |
273 | + ] | |
274 | + ) | |
275 | + ->andWhere( | |
276 | + [ | |
277 | + '!=', | |
278 | + 'product_variant.stock', | |
279 | + 0, | |
280 | + ] | |
281 | + ); | |
282 | + $query3 = ( new Query() )->select( | |
283 | + [ | |
284 | + 'tax_option.*', | |
285 | + 'tax_option_lang.alias as option_alias', | |
286 | + 'tax_group_lang.alias as group_alias', | |
287 | + 'tax_option_lang.value as value', | |
288 | + 'tax_option.sort AS tax_option_sort', | |
289 | + 'tax_group.sort AS tax_group_sort', | |
290 | + ] | |
291 | + ) | |
292 | + ->from([ 'tax_option' ]) | |
293 | + ->where([ 'tax_option.id' => $query1->union($query2) ]) | |
294 | + ->innerJoin('tax_group', 'tax_group.id = tax_option.tax_group_id') | |
295 | + ->innerJoin('tax_option_lang', 'tax_option.id = tax_option_lang.tax_option_id') | |
296 | + ->innerJoin('tax_group_lang', 'tax_group.id = tax_group_lang.tax_group_id') | |
297 | + ->andWhere([ 'tax_option_lang.language_id' => $language_id ]) | |
298 | + ->andWhere([ 'tax_group_lang.language_id' => $language_id ]) | |
299 | + ->orderBy('tax_option.sort, tax_group.sort'); | |
300 | + return $query3; | |
301 | + } | |
302 | + | |
303 | + /** | |
304 | + * Get query to get all TaxGroup for current Category | |
305 | + * | |
306 | + * @return ActiveQuery | |
307 | + */ | |
308 | + public function getTaxGroups() | |
309 | + { | |
310 | + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) | |
311 | + ->viaTable('tax_group_to_category', [ 'category_id' => 'id' ]); | |
312 | + } | |
313 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/CategoryLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "category_lang". | |
11 | + * @property integer $category_id | |
12 | + * @property integer $language_id | |
13 | + * @property string $title | |
14 | + * @property string $meta_title | |
15 | + * @property string $meta_robots | |
16 | + * @property string $meta_description | |
17 | + * @property string $seo_text | |
18 | + * @property string $h1 | |
19 | + * @property Category $category | |
20 | + * @property Language $language | |
21 | + */ | |
22 | + class CategoryLang extends ActiveRecord | |
23 | + { | |
24 | + | |
25 | + public static function primaryKey() | |
26 | + { | |
27 | + return [ | |
28 | + 'category_id', | |
29 | + 'language_id', | |
30 | + ]; | |
31 | + } | |
32 | + | |
33 | + /** | |
34 | + * @inheritdoc | |
35 | + */ | |
36 | + public static function tableName() | |
37 | + { | |
38 | + return 'category_lang'; | |
39 | + } | |
40 | + | |
41 | + public function behaviors() | |
42 | + { | |
43 | + return [ | |
44 | + 'slug' => [ | |
45 | + 'class' => 'common\behaviors\Slug', | |
46 | + ], | |
47 | + ]; | |
48 | + } | |
49 | + | |
50 | + /** | |
51 | + * @inheritdoc | |
52 | + */ | |
53 | + public function rules() | |
54 | + { | |
55 | + return [ | |
56 | + [ | |
57 | + [ 'title' ], | |
58 | + 'required', | |
59 | + ], | |
60 | + [ | |
61 | + [ | |
62 | + 'seo_text', | |
63 | + 'alias', | |
64 | + ], | |
65 | + 'string', | |
66 | + ], | |
67 | + [ | |
68 | + [ | |
69 | + 'title', | |
70 | + 'meta_title', | |
71 | + 'meta_robots', | |
72 | + 'meta_description', | |
73 | + 'h1', | |
74 | + ], | |
75 | + 'string', | |
76 | + 'max' => 255, | |
77 | + ], | |
78 | + [ | |
79 | + [ | |
80 | + 'category_id', | |
81 | + 'language_id', | |
82 | + ], | |
83 | + 'unique', | |
84 | + 'targetAttribute' => [ | |
85 | + 'category_id', | |
86 | + 'language_id', | |
87 | + ], | |
88 | + 'message' => 'The combination of Category ID and Language ID has already been taken.', | |
89 | + ], | |
90 | + [ | |
91 | + [ 'category_id' ], | |
92 | + 'exist', | |
93 | + 'skipOnError' => true, | |
94 | + 'targetClass' => Category::className(), | |
95 | + 'targetAttribute' => [ 'category_id' => 'id' ], | |
96 | + ], | |
97 | + [ | |
98 | + [ 'language_id' ], | |
99 | + 'exist', | |
100 | + 'skipOnError' => true, | |
101 | + 'targetClass' => Language::className(), | |
102 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
103 | + ], | |
104 | + ]; | |
105 | + } | |
106 | + | |
107 | + /** | |
108 | + * @inheritdoc | |
109 | + */ | |
110 | + public function attributeLabels() | |
111 | + { | |
112 | + return [ | |
113 | + 'category_id' => Yii::t('app', 'Category ID'), | |
114 | + 'language_id' => Yii::t('app', 'Language ID'), | |
115 | + 'title' => Yii::t('app', 'Name'), | |
116 | + 'meta_title' => Yii::t('app', 'Meta Title'), | |
117 | + 'meta_robots' => Yii::t('app', 'Meta Robots'), | |
118 | + 'meta_description' => Yii::t('app', 'Meta Desc'), | |
119 | + 'seo_text' => Yii::t('app', 'Seo Text'), | |
120 | + 'h1' => Yii::t('app', 'H1'), | |
121 | + ]; | |
122 | + } | |
123 | + | |
124 | + /** | |
125 | + * @return \yii\db\ActiveQuery | |
126 | + */ | |
127 | + public function getCategory() | |
128 | + { | |
129 | + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]); | |
130 | + } | |
131 | + | |
132 | + /** | |
133 | + * @return \yii\db\ActiveQuery | |
134 | + */ | |
135 | + public function getLanguage() | |
136 | + { | |
137 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
138 | + } | |
139 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/CategoryQuery.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\components\artboxtree\ArtboxTreeQueryTrait; | |
6 | + use yii\db\ActiveQuery; | |
7 | + | |
8 | + /** | |
9 | + * This is the ActiveQuery class for [[Category]]. | |
10 | + * | |
11 | + * @see Category | |
12 | + */ | |
13 | + class CategoryQuery extends ActiveQuery | |
14 | + { | |
15 | + use ArtboxTreeQueryTrait; | |
16 | + | |
17 | + /** | |
18 | + * @inheritdoc | |
19 | + * @return Category[]|array | |
20 | + */ | |
21 | + public function all($db = null) | |
22 | + { | |
23 | + return parent::all($db); | |
24 | + } | |
25 | + | |
26 | + /** | |
27 | + * @inheritdoc | |
28 | + * @return Category|array|null | |
29 | + */ | |
30 | + public function one($db = null) | |
31 | + { | |
32 | + return parent::one($db); | |
33 | + } | |
34 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/CategorySearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * CategorySearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\Category`. | |
11 | + */ | |
12 | + class CategorySearch extends Category | |
13 | + { | |
14 | + | |
15 | + public $categoryName; | |
16 | + | |
17 | + public function behaviors() | |
18 | + { | |
19 | + return []; | |
20 | + } | |
21 | + | |
22 | + /** | |
23 | + * @inheritdoc | |
24 | + */ | |
25 | + public function rules() | |
26 | + { | |
27 | + return [ | |
28 | + [ | |
29 | + [ 'categoryName' ], | |
30 | + 'safe', | |
31 | + ], | |
32 | + [ | |
33 | + [ 'id' ], | |
34 | + 'integer', | |
35 | + ], | |
36 | + ]; | |
37 | + } | |
38 | + | |
39 | + /** | |
40 | + * @inheritdoc | |
41 | + */ | |
42 | + public function scenarios() | |
43 | + { | |
44 | + // bypass scenarios() implementation in the parent class | |
45 | + return Model::scenarios(); | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * Creates data provider instance with search query applied | |
50 | + * | |
51 | + * @param array $params | |
52 | + * | |
53 | + * @return ActiveDataProvider | |
54 | + */ | |
55 | + public function search($params) | |
56 | + { | |
57 | + $query = Category::find() | |
58 | + ->joinWith('lang'); | |
59 | + | |
60 | + $dataProvider = new ActiveDataProvider( | |
61 | + [ | |
62 | + 'query' => $query, | |
63 | + 'sort' => false, | |
64 | + ] | |
65 | + ); | |
66 | + | |
67 | + $this->load($params); | |
68 | + | |
69 | + /*if (!$this->validate()) { | |
70 | + // uncomment the following line if you do not want to return any records when validation fails | |
71 | + // $query->where('0=1'); | |
72 | + return $dataProvider; | |
73 | + }*/ | |
74 | + | |
75 | + // grid filtering conditions | |
76 | + $query->andFilterWhere( | |
77 | + [ | |
78 | + 'category.id' => $this->id, | |
79 | + ] | |
80 | + ) | |
81 | + ->andFilterWhere( | |
82 | + [ | |
83 | + 'ilike', | |
84 | + 'category_lang.title', | |
85 | + $this->categoryName, | |
86 | + ] | |
87 | + ); | |
88 | + | |
89 | + $query->orderBy( | |
90 | + [ | |
91 | + 'category.path' => SORT_ASC, | |
92 | + 'category.depth' => SORT_ASC, | |
93 | + 'category.id' => SORT_ASC, | |
94 | + ] | |
95 | + ); | |
96 | + | |
97 | + return $dataProvider; | |
98 | + } | |
99 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/Export.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use artweb\artbox\ecommerce\models\TaxOption; | |
7 | + use yii\base\Model; | |
8 | + | |
9 | + class Export extends Model | |
10 | + { | |
11 | + /** | |
12 | + * Language ID to export language tables | |
13 | + * | |
14 | + * @var int $lang | |
15 | + */ | |
16 | + public $lang; | |
17 | + | |
18 | + public $file; | |
19 | + | |
20 | + public $errors = []; | |
21 | + | |
22 | + public $output = []; | |
23 | + | |
24 | + /** | |
25 | + * @inheritdoc | |
26 | + */ | |
27 | + public function rules() | |
28 | + { | |
29 | + return [ | |
30 | + [ | |
31 | + 'lang', | |
32 | + 'integer', | |
33 | + ], | |
34 | + [ | |
35 | + 'lang', | |
36 | + 'default', | |
37 | + 'value' => Language::getCurrent()->id, | |
38 | + ], | |
39 | + ]; | |
40 | + } | |
41 | + | |
42 | + /** | |
43 | + * Perform product export | |
44 | + * | |
45 | + * @param null|string $filename Export csv file name | |
46 | + * @param int $from Product start | |
47 | + * | |
48 | + * @return array | |
49 | + */ | |
50 | + public function process($filename = null, $from = 0) | |
51 | + { | |
52 | + $limit = 100; | |
53 | + | |
54 | + if (empty( $filename )) { | |
55 | + $filename = 'products_' . date('d_m_Y_H_i') . '.csv'; | |
56 | + $handle = fopen(\Yii::getAlias('@storage/sync/') . $filename, "w"); | |
57 | + } else { | |
58 | + $handle = fopen(\Yii::getAlias('@storage/sync/') . $filename, "a"); | |
59 | + } | |
60 | + | |
61 | + $language = Language::findOne(\Yii::$app->session->get('export_lang', Language::getDefaultLanguage()->id)); | |
62 | + Language::setCurrent($language->url); | |
63 | + | |
64 | + /** | |
65 | + * @var Product[] $products | |
66 | + */ | |
67 | + $products = Product::find() | |
68 | + ->with('variantsWithFilters', 'brand.lang', 'categories.lang', 'filters', 'images') | |
69 | + ->joinWith('lang', true, 'INNER JOIN') | |
70 | + ->limit($limit) | |
71 | + ->offset($from) | |
72 | + ->all(); | |
73 | + $filesize = Product::find() | |
74 | + ->joinWith('lang', true, 'INNER JOIN') | |
75 | + ->count(); | |
76 | + foreach ($products as $product) { | |
77 | + $mods = []; | |
78 | + $filterString = $this->convertFilterToString($product->filters); | |
79 | + | |
80 | + foreach ($product->variantsWithFilters as $variant) { | |
81 | + /** | |
82 | + * @var ProductVariant $variant | |
83 | + */ | |
84 | + $color = $variant->lang->title; | |
85 | + $mods[] = $variant->sku . $this->generateID( | |
86 | + $variant->remote_id | |
87 | + ) . '=' . $this->convertFilterToString( | |
88 | + $variant->filters | |
89 | + ) . '=' . $color . '=' . ( ( !empty( $variant->image ) ) ? $variant->image->image : '' ) . '=' . $variant->stock; | |
90 | + } | |
91 | + | |
92 | + $fotos = []; | |
93 | + foreach ($product->images as $image) { | |
94 | + $fotos[] = $image->image; | |
95 | + } | |
96 | + | |
97 | + $categories = []; | |
98 | + foreach ($product->categories as $value) { | |
99 | + $categories[] = $value->lang->title . $this->generateID($value->remote_id); | |
100 | + } | |
101 | + | |
102 | + $categories = implode(',', $categories); | |
103 | + | |
104 | + $list = [ | |
105 | + $categories, | |
106 | + //A - категории через запятую Название(remote_id) | |
107 | + ( ( !empty( $product->brand ) ) ? $product->brand->lang->title . $this->generateID( | |
108 | + $product->brand->remote_id | |
109 | + ) : '' ), | |
110 | + //B - бренд Название(remote_id) | |
111 | + $product->lang->title . $this->generateID($product->remote_id), | |
112 | + //C - название товара Название(remote_id) | |
113 | + ( ( !empty( $product->lang->description ) ) ? $product->lang->description : '' ), | |
114 | + //D - описание товара Описание(remote_id) | |
115 | + $filterString, | |
116 | + //E - характеристики товара. Структура: [Группа1(remote_id):Характеристика11(remote_id),Характеристика12(remote_id)]*[Группа2(remote_id):Характеристика21(remote_id),Характеристика22(remote_id)] | |
117 | + ( !empty( $product->variant ) ) ? $product->variant->price_old : '', | |
118 | + //F - страрая цена | |
119 | + ( !empty( $product->variant ) ) ? $product->variant->price : '', | |
120 | + //G - новая цена | |
121 | + intval($product->is_discount), | |
122 | + //H - товар акционный (1/0) | |
123 | + '', | |
124 | + //I - пустой | |
125 | + intval($product->is_new), | |
126 | + //J - товар новинка | |
127 | + intval($product->is_top), | |
128 | + //K - товар в топе | |
129 | + $product->video, | |
130 | + //L - ссылка на видео (iframe) | |
131 | + implode(',', $fotos), | |
132 | + //M - название файлов через запятую, картинки должны хранится в /storage/sync/product_images | |
133 | + // Все последующие модификации: SKU(remote_id)=[Группа1(remote_id):Характеристика11(remote_id),Характеристика12(remote_id)]*[Группа2(remote_id):Характеристика21(remote_id),Характеристика22(remote_id)]=Название=Изображение=Остаток | |
134 | + ]; | |
135 | + $to_write = array_merge($list, $mods); | |
136 | + fputcsv($handle, $to_write, ';'); | |
137 | + unset( $product ); | |
138 | + } | |
139 | + | |
140 | + fclose($handle); | |
141 | + | |
142 | + $from += $limit; | |
143 | + $end = false; | |
144 | + if ($from > $filesize) { | |
145 | + $end = true; | |
146 | + } | |
147 | + | |
148 | + $result = [ | |
149 | + 'end' => $end, | |
150 | + 'from' => $from, | |
151 | + 'totalsize' => $filesize, | |
152 | + 'filename' => $filename, | |
153 | + ]; | |
154 | + | |
155 | + if ($end) { | |
156 | + $result = array_merge( | |
157 | + $result, | |
158 | + [ | |
159 | + 'link' => '/storage/sync/' . $filename, | |
160 | + ] | |
161 | + ); | |
162 | + } | |
163 | + | |
164 | + return $result; | |
165 | + } | |
166 | + | |
167 | + /** | |
168 | + * Stringify filters for export | |
169 | + * * Result: [filterName1:filterValue11,filterValue12]*[filterName2:filterValue21,filterValue22] | |
170 | + * | |
171 | + * @param $filters | |
172 | + * | |
173 | + * @return string | |
174 | + */ | |
175 | + public function convertFilterToString($filters) | |
176 | + { | |
177 | + $filtersArray = []; | |
178 | + /** | |
179 | + * @var TaxOption[] $filters | |
180 | + */ | |
181 | + foreach ($filters as $filter) { | |
182 | + $filtersArray[ $filter->taxGroup->lang->title . $this->generateID( | |
183 | + $filter->taxGroup->remote_id | |
184 | + ) ][] = $filter->lang->value . $this->generateID($filter->remote_id); | |
185 | + } | |
186 | + $filterString = []; | |
187 | + | |
188 | + foreach ($filtersArray as $filterName => $filterRows) { | |
189 | + $row = implode(',', $filterRows); | |
190 | + $filterString[] = "[{$filterName}:{$row}]"; | |
191 | + } | |
192 | + return implode('*', $filterString); | |
193 | + } | |
194 | + | |
195 | + /** | |
196 | + * Generate remote ID string | |
197 | + * | |
198 | + * @param string $id Remote ID | |
199 | + * | |
200 | + * @return string Formatted remote ID | |
201 | + */ | |
202 | + private function generateID(string $id):string | |
203 | + { | |
204 | + return sprintf('(#%s#)', $id); | |
205 | + } | |
206 | + } | |
207 | + | |
0 | 208 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/models/Import.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
7 | + use artweb\artbox\ecommerce\models\TaxOption; | |
8 | + use Yii; | |
9 | + use yii\base\Model; | |
10 | + use yii\helpers\ArrayHelper; | |
11 | + | |
12 | + /** | |
13 | + * Class Import | |
14 | + * | |
15 | + * @package artweb\artbox\ecommerce\models | |
16 | + */ | |
17 | + class Import extends Model | |
18 | + { | |
19 | + /** | |
20 | + * Import csv file | |
21 | + * | |
22 | + * @var string $file | |
23 | + */ | |
24 | + public $file; | |
25 | + | |
26 | + /** | |
27 | + * Import type | |
28 | + * * product | |
29 | + * * price | |
30 | + * | |
31 | + * @var string $type | |
32 | + */ | |
33 | + public $type; | |
34 | + | |
35 | + /** | |
36 | + * Import language ID | |
37 | + * | |
38 | + * @var int $lang | |
39 | + */ | |
40 | + public $lang; | |
41 | + | |
42 | + public $errors = []; | |
43 | + | |
44 | + public $output = []; | |
45 | + | |
46 | + /** | |
47 | + * @inheritdoc | |
48 | + */ | |
49 | + public function rules() | |
50 | + { | |
51 | + return [ | |
52 | + [ | |
53 | + [ | |
54 | + 'type', | |
55 | + 'lang', | |
56 | + ], | |
57 | + 'required', | |
58 | + ], | |
59 | + [ | |
60 | + [ 'lang' ], | |
61 | + 'integer', | |
62 | + ], | |
63 | + [ | |
64 | + [ 'type' ], | |
65 | + 'string', | |
66 | + ], | |
67 | + [ | |
68 | + [ 'file' ], | |
69 | + 'file', | |
70 | + 'extensions' => 'csv', | |
71 | + ], | |
72 | + ]; | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * @inheritdoc | |
77 | + */ | |
78 | + public function attributeLabels() | |
79 | + { | |
80 | + return [ | |
81 | + 'file' => Yii::t('product', 'File'), | |
82 | + ]; | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * Get import type | |
87 | + * | |
88 | + * @see Import::type | |
89 | + * @return string | |
90 | + */ | |
91 | + public function getType() | |
92 | + { | |
93 | + if (!$this->type) { | |
94 | + $this->type = 'products'; | |
95 | + } | |
96 | + return $this->type; | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * Import prices | |
101 | + * | |
102 | + * @param int $from Start row | |
103 | + * @param null $limit Row limit | |
104 | + * | |
105 | + * @return array|bool Array if OK, false otherwise | |
106 | + */ | |
107 | + public function goPrices($from = 0, $limit = null) | |
108 | + { | |
109 | + set_time_limit(0); | |
110 | + | |
111 | + if (!( $handle = $this->getProductsFile('uploadFilePrices') )) { | |
112 | + $this->errors[] = 'File not found'; | |
113 | + return false; | |
114 | + } | |
115 | + | |
116 | + $filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices')); | |
117 | + if ($from) { | |
118 | + fseek($handle, $from); | |
119 | + } | |
120 | + | |
121 | + $j = 0; | |
122 | + | |
123 | + $is_utf = ( preg_match( | |
124 | + '//u', | |
125 | + file_get_contents( | |
126 | + Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices'), | |
127 | + null, | |
128 | + null, | |
129 | + null, | |
130 | + 1000000 | |
131 | + ) | |
132 | + ) ); | |
133 | + | |
134 | + while (( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) { | |
135 | + foreach ($data as &$value) { | |
136 | + if (!$is_utf) { | |
137 | + $value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value); | |
138 | + } | |
139 | + $value = trim($value); | |
140 | + } | |
141 | + | |
142 | + // данные строк | |
143 | + $modification_code = @$data[ 0 ]; | |
144 | + $price = floatval(@$data[ 1 ]); | |
145 | + $price_promo = floatval(@$data[ 2 ]); | |
146 | + $count = intval(@$data[ 3 ]); | |
147 | + $city_name = @$data[ 4 ]; | |
148 | + $product_title = @$data[ 5 ]; | |
149 | + | |
150 | + if (empty ( $modification_code )) { | |
151 | + continue; | |
152 | + } | |
153 | + // товары в пути | |
154 | + if (empty ( $city_name )) { | |
155 | + $this->output[] = 'Товар ' . $product_title . ' в пути'; | |
156 | + continue; | |
157 | + } | |
158 | + /** | |
159 | + * @var ProductVariant $productVariant | |
160 | + */ | |
161 | + if (( $productVariant = ProductVariant::find() | |
162 | + ->filterWhere([ 'sku' => $modification_code ]) | |
163 | + ->one() ) === null | |
164 | + ) { | |
165 | + $this->output[] = 'Для товара ' . $product_title . ' не найдено соотвествие'; | |
166 | + continue; | |
167 | + } | |
168 | + // ===== Set stock ==== | |
169 | + if ($city_name) { | |
170 | + if (( $stock = Stock::find() | |
171 | + ->filterWhere([ 'title' => trim($city_name) ]) | |
172 | + ->one() ) === null | |
173 | + ) { | |
174 | + // Create stock | |
175 | + $stock = new Stock(); | |
176 | + $stock->title = trim($city_name); | |
177 | + $stock->save(false); | |
178 | + } | |
179 | + | |
180 | + $productStock = ProductStock::find() | |
181 | + ->where( | |
182 | + [ | |
183 | + 'product_variant_id' => $productVariant->id, | |
184 | + 'stock_id' => $stock->id, | |
185 | + ] | |
186 | + ) | |
187 | + ->one(); | |
188 | + if (!$productStock instanceof ProductStock) { | |
189 | + $productStock = new ProductStock(); | |
190 | + $productStock->product_variant_id = $productVariant->id; | |
191 | + $productStock->stock_id = $stock->id; | |
192 | + } | |
193 | + $productStock->quantity = $count; | |
194 | + | |
195 | + $productStock->save(false); | |
196 | + $productStocks = ProductStock::find() | |
197 | + ->where( | |
198 | + [ 'product_variant_id' => $productVariant->id ] | |
199 | + ) | |
200 | + ->andWhere( | |
201 | + [ | |
202 | + '<>', | |
203 | + 'stock_id', | |
204 | + $stock->id, | |
205 | + ] | |
206 | + ) | |
207 | + ->all(); | |
208 | + | |
209 | + $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count; | |
210 | + } else { | |
211 | + | |
212 | + $productStocks = ProductStock::find() | |
213 | + ->where( | |
214 | + [ 'product_variant_id' => $productVariant->id ] | |
215 | + ) | |
216 | + ->all(); | |
217 | + | |
218 | + if ($productStocks instanceof ProductStock) { | |
219 | + $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count; | |
220 | + } else { | |
221 | + $quantity = 0; | |
222 | + } | |
223 | + | |
224 | + } | |
225 | + | |
226 | + if ($price_promo) { | |
227 | + $productVariant->price_old = $price; | |
228 | + $productVariant->price = $price_promo; | |
229 | + } else { | |
230 | + $productVariant->price = $price; | |
231 | + $productVariant->price_old = $price_promo; | |
232 | + } | |
233 | + | |
234 | + $productVariant->stock = $quantity; | |
235 | + | |
236 | + $productVariant->save(false); | |
237 | + | |
238 | + $this->output[] = '<span style="color:blue">Товар ' . $product_title . ' успешно сохранен</span>'; | |
239 | + } | |
240 | + | |
241 | + $result = [ | |
242 | + 'end' => feof($handle), | |
243 | + 'from' => ftell($handle), | |
244 | + 'totalsize' => $filesize, | |
245 | + 'items' => $this->output, | |
246 | + | |
247 | + ]; | |
248 | + | |
249 | + fclose($handle); | |
250 | + | |
251 | + if ($result[ 'end' ]) { | |
252 | + unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFilePrices')); | |
253 | + } | |
254 | + | |
255 | + return $result; | |
256 | + } | |
257 | + | |
258 | + /** | |
259 | + * Pull name and remote_id from formatted string | |
260 | + * | |
261 | + * @param string $name | |
262 | + * | |
263 | + * @return array | |
264 | + */ | |
265 | + private function parseName(string $name):array | |
266 | + { | |
267 | + $pattern = '/^(?P<name>.*)(?:\(#(?P<remote_id>\w+)#\))?$/U'; | |
268 | + $name = trim($name); | |
269 | + $matches = []; | |
270 | + if (preg_match($pattern, $name, $matches)) { | |
271 | + if (!isset( $matches[ 'remote_id' ] )) { | |
272 | + $matches[ 'remote_id' ] = ''; | |
273 | + } | |
274 | + return $matches; | |
275 | + } | |
276 | + return [ | |
277 | + 'name' => $name, | |
278 | + 'remote_id' => '', | |
279 | + ]; | |
280 | + } | |
281 | + | |
282 | + /** | |
283 | + * Save categories | |
284 | + * | |
285 | + * @param array $catalog_names | |
286 | + * | |
287 | + * @return int[] Category IDs | |
288 | + * @throws \Exception | |
289 | + */ | |
290 | + private function saveCatalog(array $catalog_names):array | |
291 | + { | |
292 | + $category_id = []; | |
293 | + | |
294 | + foreach ($catalog_names as $catalog_name) { | |
295 | + // ==== Set category ==== | |
296 | + $parsed_name = $this->parseName($catalog_name); | |
297 | + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $category = Category::find() | |
298 | + ->joinWith('lang') | |
299 | + ->andFilterWhere( | |
300 | + [ 'remote_id' => $parsed_name[ 'remote_id' ] ] | |
301 | + ) | |
302 | + ->one() ) !== null | |
303 | + ) { | |
304 | + if (!empty( $category->lang )) { | |
305 | + $category->lang->title = $parsed_name[ 'name' ]; | |
306 | + $category->lang->save(false); | |
307 | + } else { | |
308 | + throw new \Exception( | |
309 | + 'Category with ID ' . $category->id . ' and lang ' . Language::getCurrent( | |
310 | + )->id . ' doesn\'t exist' | |
311 | + ); | |
312 | + } | |
313 | + | |
314 | + } else { | |
315 | + // Create category | |
316 | + $category = new Category(); | |
317 | + $category->generateLangs(); | |
318 | + $category_langs = $category->modelLangs; | |
319 | + foreach ($category_langs as $category_lang) { | |
320 | + $category_lang->title = $parsed_name[ 'name' ]; | |
321 | + } | |
322 | + $category->remote_id = $parsed_name[ 'remote_id' ]; | |
323 | + $category->save(false); | |
324 | + } | |
325 | + $category_id[] = $category->id; | |
326 | + } | |
327 | + return $category_id; | |
328 | + } | |
329 | + | |
330 | + /** | |
331 | + * Save brand | |
332 | + * | |
333 | + * @param string|null $brand_name | |
334 | + * | |
335 | + * @return int|null New Brand ID if inserted or exist or null if skipped | |
336 | + * @throws \Exception | |
337 | + */ | |
338 | + private function saveBrand(string $brand_name = null):int | |
339 | + { | |
340 | + | |
341 | + $parsed_name = $this->parseName($brand_name); | |
342 | + if (!empty( $brand_name )) { | |
343 | + /** | |
344 | + * @var Brand $brand | |
345 | + */ | |
346 | + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $brand = Brand::find() | |
347 | + ->joinWith('lang') | |
348 | + ->andFilterWhere( | |
349 | + [ 'remote_id' => $parsed_name[ 'remote_id' ] ] | |
350 | + ) | |
351 | + ->one() ) !== null | |
352 | + ) { | |
353 | + if (!empty( $brand->lang )) { | |
354 | + $brand->lang->title = $parsed_name[ 'name' ]; | |
355 | + $brand->lang->save(false); | |
356 | + } else { | |
357 | + throw new \Exception( | |
358 | + 'Brand with ID ' . $brand->id . ' and lang ' . Language::getCurrent( | |
359 | + )->id . ' doesn\'t exist' | |
360 | + ); | |
361 | + } | |
362 | + return $brand->id; | |
363 | + } else { | |
364 | + // Create brand | |
365 | + $brand = new Brand(); | |
366 | + $brand->generateLangs(); | |
367 | + $brand_langs = $brand->modelLangs; | |
368 | + foreach ($brand_langs as $brand_lang) { | |
369 | + $brand_lang->title = $parsed_name[ 'name' ]; | |
370 | + } | |
371 | + $brand->remote_id = $parsed_name[ 'remote_id' ]; | |
372 | + $brand->save(false); | |
373 | + return $brand->id; | |
374 | + } | |
375 | + } | |
376 | + return null; | |
377 | + } | |
378 | + | |
379 | + /** | |
380 | + * Save Product or ProductVariant photoes | |
381 | + * | |
382 | + * @param string[] $fotos Photoes names | |
383 | + * @param int $product_id | |
384 | + * @param int|null $product_variant_id Null if photo for Product | |
385 | + */ | |
386 | + private function saveFotos(array $fotos, int $product_id, int $product_variant_id = null) | |
387 | + { | |
388 | + if (!empty( $fotos )) { | |
389 | + foreach ($fotos as $foto) { | |
390 | + if (empty( $foto )) { | |
391 | + continue; | |
392 | + } | |
393 | + $source_image = Yii::getAlias('@uploadDir') . '/product_images/' . urlencode($foto); | |
394 | + if (file_exists($source_image)) { | |
395 | + if (( $productImage = ProductImage::find() | |
396 | + ->andWhere([ 'image' => $foto ]) | |
397 | + ->andWhere([ 'product_id' => $product_id ]) | |
398 | + ->andFilterWhere( | |
399 | + [ 'product_variant_id' => $product_variant_id ] | |
400 | + ) | |
401 | + ->one() ) === null | |
402 | + ) { | |
403 | + copy($source_image, Yii::getAlias('@productsDir') . "/" . $foto); | |
404 | + $productImage = new ProductImage(); | |
405 | + $productImage->product_id = $product_id; | |
406 | + $productImage->product_variant_id = $product_variant_id; | |
407 | + $productImage->image = $foto; | |
408 | + $productImage->save(false); | |
409 | + } | |
410 | + } | |
411 | + } | |
412 | + } | |
413 | + } | |
414 | + | |
415 | + /** | |
416 | + * Save ProductVariants | |
417 | + * | |
418 | + * @param array $data ProductVariats data | |
419 | + * @param float $product_cost_old Old price | |
420 | + * @param int $product_id Product ID | |
421 | + * @param array $category_id Ca | |
422 | + * @param float|null $product_cost | |
423 | + * | |
424 | + * @return int[] Array of ProductVariants IDs | |
425 | + * @throws \Exception | |
426 | + */ | |
427 | + private function saveVariants( | |
428 | + array $data, | |
429 | + float $product_cost_old, | |
430 | + int $product_id, | |
431 | + array $category_id, | |
432 | + float $product_cost = null | |
433 | + ):array | |
434 | + { | |
435 | + $MOD_ARRAY = []; | |
436 | + for ($i = 13; $i < count($data); $i++) { | |
437 | + if (!empty ( $data[ $i ] )) { | |
438 | + $mod_arr = explode('=', $data[ $i ]); | |
439 | + $mod_art = $mod_arr[ 0 ]; | |
440 | + $mod_art_parsed = $this->parseName($mod_art); | |
441 | + $variant_filters = explode('*', $mod_arr[ 1 ]); | |
442 | + $mod_name = $mod_arr[ 2 ]; | |
443 | + if (empty( $mod_name )) { | |
444 | + $mod_name = $mod_art_parsed[ 'name' ]; | |
445 | + } | |
446 | + $mod_image = $mod_arr[ 3 ]; | |
447 | + $mod_stock = isset( $mod_arr[ 4 ] ) ? $mod_arr[ 4 ] : 1; | |
448 | + $mod_cost = isset( $product_cost ) ? floatval($product_cost) : 0; | |
449 | + $mod_old_cost = floatval($product_cost_old); | |
450 | + // Check product variant | |
451 | + /** | |
452 | + * @var ProductVariant $_productVariant | |
453 | + */ | |
454 | + if (( $_productVariant = ProductVariant::find() | |
455 | + ->joinWith('lang') | |
456 | + ->andFilterWhere( | |
457 | + [ 'remote_id' => $mod_art_parsed[ 'remote_id' ] ] | |
458 | + ) | |
459 | + ->andFilterWhere( | |
460 | + [ 'product_variant.product_id' => $product_id ] | |
461 | + ) | |
462 | + ->one() ) === null | |
463 | + ) { | |
464 | + $_productVariant = new ProductVariant(); | |
465 | + $_productVariant->product_id = $product_id; | |
466 | + if (!empty( $mod_art_parsed[ 'remote_id' ] )) { | |
467 | + $_productVariant->remote_id = $mod_art_parsed[ 'remote_id' ]; | |
468 | + } | |
469 | + $_productVariant->generateLangs(); | |
470 | + $product_variant_langs = $_productVariant->modelLangs; | |
471 | + foreach ($product_variant_langs as $product_variant_lang) { | |
472 | + $product_variant_lang->title = $mod_name; | |
473 | + } | |
474 | + } else { | |
475 | + if (!empty( $_productVariant->lang )) { | |
476 | + $_productVariant->lang->title = $mod_name; | |
477 | + $_productVariant->lang->save(false); | |
478 | + } else { | |
479 | + throw new \Exception( | |
480 | + 'Product variant with ID ' . $_productVariant->id . ' and lang ' . Language::getCurrent( | |
481 | + )->id . ' doesn\'t exist' | |
482 | + ); | |
483 | + } | |
484 | + } | |
485 | + $_productVariant->product_unit_id = 1; | |
486 | + $_productVariant->sku = $mod_art_parsed[ 'name' ]; | |
487 | + $_productVariant->price = $mod_cost; | |
488 | + $_productVariant->price_old = $mod_old_cost; | |
489 | + $_productVariant->stock = $mod_stock; | |
490 | + | |
491 | + if (!empty ( $variant_filters )) { | |
492 | + $variants_options = $this->saveFilters($variant_filters, 1, $category_id); | |
493 | + } | |
494 | + | |
495 | + if (isset( $variants_options ) && !empty( $variants_options )) { | |
496 | + $_productVariant->options = $variants_options; | |
497 | + } | |
498 | + | |
499 | + /** | |
500 | + * @todo set to false | |
501 | + */ | |
502 | + $_productVariant->save(false); | |
503 | + | |
504 | + $MOD_ARRAY[] = $_productVariant->id; | |
505 | + $this->saveFotos([ $mod_image ], $product_id, $_productVariant->id); | |
506 | + } | |
507 | + } | |
508 | + return $MOD_ARRAY; | |
509 | + } | |
510 | + | |
511 | + /** | |
512 | + * Perform product import | |
513 | + * | |
514 | + * @param int $from Begin row | |
515 | + * @param null $limit Row limit | |
516 | + * | |
517 | + * @return array|bool Array if OK, false if error | |
518 | + */ | |
519 | + public function goProducts($from = 0, $limit = null) | |
520 | + { | |
521 | + set_time_limit(0); | |
522 | + | |
523 | + if (!( $handle = $this->getProductsFile('uploadFileProducts') )) { | |
524 | + $this->errors[] = 'File not found'; | |
525 | + return false; | |
526 | + } | |
527 | + | |
528 | + $filesize = filesize(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts')); | |
529 | + | |
530 | + if ($from) { | |
531 | + fseek($handle, $from); | |
532 | + } | |
533 | + | |
534 | + $j = 0; | |
535 | + | |
536 | + $is_utf = ( preg_match( | |
537 | + '//u', | |
538 | + file_get_contents( | |
539 | + Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts'), | |
540 | + null, | |
541 | + null, | |
542 | + null, | |
543 | + 1000000 | |
544 | + ) | |
545 | + ) ); | |
546 | + | |
547 | + $result_items = []; | |
548 | + | |
549 | + while (( empty( $limit ) || $j++ < $limit ) && ( $data = fgetcsv($handle, 10000, ";") ) !== false) { | |
550 | + try { | |
551 | + | |
552 | + foreach ($data as &$value) { | |
553 | + if (!$is_utf) { | |
554 | + $value = iconv('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value); | |
555 | + } | |
556 | + $value = trim($value); | |
557 | + } | |
558 | + // будет всегда 19 элементов | |
559 | + for ($i = 0; $i <= 18; $i++) { | |
560 | + if (!isset ( $data[ $i ] )) { | |
561 | + $data[ $i ] = null; | |
562 | + } | |
563 | + } | |
564 | + // 1 Группа (категория) | |
565 | + $catalog_names = explode(',', $data[ 0 ]); | |
566 | + if (empty ( $catalog_names )) { | |
567 | + $result_items[] = "Не указана категория (строка $j)"; | |
568 | + continue; | |
569 | + } | |
570 | + | |
571 | + // 2 Бренд | |
572 | + $brand_name = $data[ 1 ]; | |
573 | + // if(empty ( $brand_name )) { | |
574 | + // $result_items[] = "Не указан бренд (строка $j)"; | |
575 | + // continue; | |
576 | + // } | |
577 | + | |
578 | + // 3 Название товара | |
579 | + $product_name = $data[ 2 ]; | |
580 | + if (empty ( $product_name )) { | |
581 | + $result_items[] = "Не указано наименование товара (строка $j)"; | |
582 | + continue; | |
583 | + } | |
584 | + | |
585 | + // 5 Описание товара | |
586 | + $product_body = $data[ 3 ]; | |
587 | + | |
588 | + // 6 Фильтр | |
589 | + $filters = explode('*', $data[ 4 ]); | |
590 | + | |
591 | + // 11 Цена акция | |
592 | + $product_cost_old = floatval($data[ 6 ]); | |
593 | + | |
594 | + $product_cost = null; | |
595 | + // 10 Цена | |
596 | + if ($product_cost_old) { | |
597 | + $product_cost_old = floatval($data[ 5 ]); | |
598 | + $product_cost = floatval($data[ 6 ]); | |
599 | + } | |
600 | + | |
601 | + // 12 Акция | |
602 | + $product_discount = (bool) $data[ 7 ]; | |
603 | + | |
604 | + // 13 Сопуд. Тов. | |
605 | + $similar = explode(',', $data[ 8 ]); | |
606 | + | |
607 | + // 14 Новинки | |
608 | + $product_new = (bool) $data[ 9 ]; | |
609 | + | |
610 | + // 15 Топ продаж | |
611 | + $product_top = (bool) $data[ 10 ]; | |
612 | + | |
613 | + // 17 ВИДЕО КОД | |
614 | + $product_video = $data[ 11 ]; | |
615 | + | |
616 | + // 18 Галлерея фото | |
617 | + $fotos = []; | |
618 | + if (trim($data[ 12 ])) { | |
619 | + $fotos = explode(',', trim($data[ 12 ])); | |
620 | + } | |
621 | + | |
622 | + // $lang = \Yii::$app->session->get('export_lang', Language::getDefaultLanguage()->id); | |
623 | + // /** | |
624 | + // * @var Language $language | |
625 | + // */ | |
626 | + // $language = Language::find() | |
627 | + // ->where([ 'id' => $lang ]) | |
628 | + // ->one(); | |
629 | + // Language::setCurrent($language->url); | |
630 | + $categories = $this->saveCatalog($catalog_names); | |
631 | + | |
632 | + $brand_id = $this->saveBrand($brand_name); | |
633 | + | |
634 | + $options = []; | |
635 | + if (!empty ( $filters )) { | |
636 | + $options = $this->saveFilters($filters, 0, $categories); | |
637 | + } | |
638 | + $parsed_name = $this->parseName($product_name); | |
639 | + /** | |
640 | + * @var Product $_product | |
641 | + */ | |
642 | + if (!empty( $parsed_name[ 'remote_id' ] ) && ( $_product = Product::find() | |
643 | + ->joinWith('lang') | |
644 | + ->andFilterWhere( | |
645 | + [ 'remote_id' => $parsed_name[ 'remote_id' ] ] | |
646 | + ) | |
647 | + ->one() ) !== null | |
648 | + ) { | |
649 | + if (!empty( $_product->lang )) { | |
650 | + $_product->lang->title = $parsed_name[ 'name' ]; | |
651 | + $_product->lang->description = $product_body; | |
652 | + $_product->lang->save(false); | |
653 | + } else { | |
654 | + throw new \Exception( | |
655 | + 'Product with ID ' . $_product->id . ' and lang ' . Language::getCurrent( | |
656 | + )->id . ' doesn\'t exist' | |
657 | + ); | |
658 | + } | |
659 | + } else { | |
660 | + $_product = new Product(); | |
661 | + $_product->generateLangs(); | |
662 | + $product_langs = $_product->modelLangs; | |
663 | + foreach ($product_langs as $product_lang) { | |
664 | + $product_lang->title = $parsed_name[ 'name' ]; | |
665 | + $product_lang->description = $product_body; | |
666 | + } | |
667 | + } | |
668 | + | |
669 | + $is_new_product = empty( $_product->id ); | |
670 | + | |
671 | + $_product->categories = $categories; | |
672 | + | |
673 | + $_product->brand_id = $brand_id; | |
674 | + | |
675 | + $_product->video = $product_video; | |
676 | + $_product->is_top = $product_top; | |
677 | + $_product->is_discount = $product_discount; | |
678 | + $_product->is_new = $product_new; | |
679 | + if (!empty( $options )) { | |
680 | + $_product->options = $options; | |
681 | + } | |
682 | + | |
683 | + if (!empty( $_product->lang )) { | |
684 | + $product_name_inserted = $_product->lang->title; | |
685 | + } else { | |
686 | + $product_name_inserted = $_product->modelLangs[ Language::$current->id ]->title; | |
687 | + } | |
688 | + | |
689 | + if (( $_product->save(false) === false ) || !$_product->transactionStatus) { | |
690 | + $result_items[] = 'Product #' . $product_name_inserted . ' not saved' . " (line $j)"; | |
691 | + continue; | |
692 | + } | |
693 | + | |
694 | + $this->saveFotos($fotos, $_product->id); | |
695 | + // нужно для проставления характеристик относящихся к модификациям | |
696 | + | |
697 | + $this->saveVariants($data, $product_cost_old, $_product->id, $_product->categories, $product_cost); | |
698 | + | |
699 | + // $_product->save(false); | |
700 | + | |
701 | + $result_items[] = "Product {$product_name_inserted} #{$_product->id} saved (" . ( $is_new_product ? 'new product' : 'exists product' ) . ")" . " (line $j)"; | |
702 | + | |
703 | + } catch (\Exception $e) { | |
704 | + $result_items[] = $e->getMessage() . '(line ' . $j . ')'; | |
705 | + } | |
706 | + | |
707 | + } | |
708 | + | |
709 | + $result = [ | |
710 | + 'end' => feof($handle), | |
711 | + 'from' => ftell($handle), | |
712 | + 'totalsize' => $filesize, | |
713 | + 'items' => $result_items, | |
714 | + ]; | |
715 | + | |
716 | + fclose($handle); | |
717 | + | |
718 | + if ($result[ 'end' ]) { | |
719 | + // unlink(Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@uploadFileProducts')); | |
720 | + } | |
721 | + | |
722 | + return $result; | |
723 | + } | |
724 | + | |
725 | + /** | |
726 | + * Get import file | |
727 | + * | |
728 | + * @param string $file_type | |
729 | + * | |
730 | + * @return bool|resource false if File not found and file resource if OK | |
731 | + */ | |
732 | + private function getProductsFile($file_type) | |
733 | + { | |
734 | + $filename = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@' . $file_type); | |
735 | + if (!is_file($filename)) { | |
736 | + $this->errors[] = "File $filename not found"; | |
737 | + return false; | |
738 | + } | |
739 | + return fopen($filename, 'r'); | |
740 | + } | |
741 | + | |
742 | + /** | |
743 | + * Save filters | |
744 | + * | |
745 | + * @param array $filters array of filters like [['pol'='мужской'],['god' = | |
746 | + * '2013'],['volume'='25 л']*['size'='49 x 30 x | |
747 | + * 20см'],['composition'='600D полиэстер']] | |
748 | + * @param int $level 0 for products and 1 for product variant | |
749 | + * @param int[] $catalog_names array catalogs id | |
750 | + * | |
751 | + * @return array | |
752 | + * @throws \Exception | |
753 | + */ | |
754 | + private function saveFilters(array $filters, int $level, array $catalog_names):array | |
755 | + { | |
756 | + $options = []; | |
757 | + foreach ($filters as $filter) { | |
758 | + | |
759 | + preg_match_all('/\[(.*):(.*)\]/', $filter, $filter); | |
760 | + | |
761 | + if (empty( $filter[ 1 ][ 0 ] )) { | |
762 | + continue; | |
763 | + } | |
764 | + $filter_name = trim($filter[ 1 ][ 0 ]); | |
765 | + $parsed_group_name = $this->parseName($filter_name); | |
766 | + | |
767 | + /** | |
768 | + * @var TaxGroup $taxGroup | |
769 | + */ | |
770 | + if (!empty( $parsed_group_name[ 'remote_id' ] ) && ( $taxGroup = TaxGroup::find() | |
771 | + ->joinWith('lang') | |
772 | + ->andFilterWhere( | |
773 | + [ 'remote_id' => $parsed_group_name[ 'remote_id' ] ] | |
774 | + ) | |
775 | + ->one() ) !== null | |
776 | + ) { | |
777 | + if (!empty( $taxGroup->lang )) { | |
778 | + $taxGroup->lang->title = $parsed_group_name[ 'name' ]; | |
779 | + $taxGroup->lang->save(false); | |
780 | + } else { | |
781 | + throw new \Exception( | |
782 | + 'Tax group with ID ' . $taxGroup->id . ' and lang ' . Language::getCurrent( | |
783 | + )->id . ' doesn\'t exist' | |
784 | + ); | |
785 | + } | |
786 | + } else { | |
787 | + $taxGroup = new TaxGroup(); | |
788 | + $taxGroup->generateLangs(); | |
789 | + $tax_group_langs = $taxGroup->modelLangs; | |
790 | + foreach ($tax_group_langs as $tax_group_lang) { | |
791 | + $tax_group_lang->title = $parsed_group_name[ 'name' ]; | |
792 | + } | |
793 | + $taxGroup->level = $level; | |
794 | + $taxGroup->categories = $catalog_names; | |
795 | + $taxGroup->is_filter = false; | |
796 | + $taxGroup->save(false); | |
797 | + } | |
798 | + $filters_options = explode(',', $filter[ 2 ][ 0 ]); | |
799 | + foreach ($filters_options as $filter_options) { | |
800 | + $parsed_option_name = $this->parseName($filter_options); | |
801 | + /** | |
802 | + * @var TaxOption $option | |
803 | + */ | |
804 | + | |
805 | + if (!empty( $parsed_option_name[ 'remote_id' ] ) && ( $option = TaxOption::find() | |
806 | + ->joinWith('lang') | |
807 | + ->andFilterWhere( | |
808 | + [ 'remote_id' => $parsed_option_name[ 'remote_id' ] ] | |
809 | + ) | |
810 | + ->andFilterWhere( | |
811 | + [ 'tax_group_id' => $taxGroup->id ] | |
812 | + ) | |
813 | + ->one() ) !== null | |
814 | + ) { | |
815 | + if (!empty( $option->lang )) { | |
816 | + $option->lang->value = $parsed_option_name[ 'name' ]; | |
817 | + $option->lang->save(false); | |
818 | + } else { | |
819 | + throw new \Exception( | |
820 | + 'Tax option with ID ' . $option->id . ' and lang ' . Language::getCurrent( | |
821 | + )->id . ' doesn\'t exist' | |
822 | + ); | |
823 | + } | |
824 | + } else { | |
825 | + // Create option | |
826 | + $option = new TaxOption(); | |
827 | + $option->generateLangs(); | |
828 | + $option_langs = $option->modelLangs; | |
829 | + foreach ($option_langs as $option_lang) { | |
830 | + $option_lang->value = $parsed_option_name[ 'name' ]; | |
831 | + } | |
832 | + $option->id = $taxGroup->id; | |
833 | + $option->save(false); | |
834 | + } | |
835 | + $options[] = $option->id; | |
836 | + } | |
837 | + } | |
838 | + return $options; | |
839 | + } | |
840 | + } | |
841 | + | |
0 | 842 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/models/Product.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\DefaultVariantBehavior; | |
6 | + use common\behaviors\MultipleImgBehavior; | |
7 | + use common\behaviors\SaveMultipleFileBehavior; | |
8 | + use common\models\ProductToRating; | |
9 | + use common\modules\comment\models\CommentModel; | |
10 | + use common\modules\language\behaviors\LanguageBehavior; | |
11 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
12 | + use artweb\artbox\ecommerce\models\TaxGroupToCategory; | |
13 | + use artweb\artbox\ecommerce\models\TaxOption; | |
14 | + use Yii; | |
15 | + use yii\base\InvalidParamException; | |
16 | + use yii\db\ActiveQuery; | |
17 | + use yii\db\ActiveRecord; | |
18 | + use yii\helpers\ArrayHelper; | |
19 | + use yii\web\NotFoundHttpException; | |
20 | + use yii\web\Request; | |
21 | + | |
22 | + /** | |
23 | + * This is the model class for table "{{%product}}". | |
24 | + * | |
25 | + * @property integer $brand_id | |
26 | + * @property integer $id | |
27 | + * @property Category $category | |
28 | + * @property Category[] $categories | |
29 | + * @property ProductVariant $variant | |
30 | + * @property ProductVariant[] $variants | |
31 | + * @property ProductVariant $productVariant | |
32 | + * @property ProductVariant[] $productVariants | |
33 | + * @property boolean $is_top | |
34 | + * @property boolean $is_new | |
35 | + * @property boolean $is_discount | |
36 | + * @property ProductToRating $averageRating | |
37 | + * @property TaxGroup[] $properties | |
38 | + * @property ProductVariant $enabledVariant | |
39 | + * @property ProductVariant[] $enabledVariants | |
40 | + * @property string $video | |
41 | + * @property TaxOption[] $options | |
42 | + * @property Brand $brand | |
43 | + * @property TaxOption[] $filters | |
44 | + * @property ProductVariant[] $variantsWithFilters | |
45 | + * @property string $remote_id | |
46 | + * @property string $fullname | |
47 | + * @property float $variantPrice | |
48 | + * @property float $enabledVariantPrice | |
49 | + * @property array $categoryNames | |
50 | + * @property Stock[] $stocks | |
51 | + * @property ProductStock[] $productStocks | |
52 | + * @property int $quantity | |
53 | + * @property TaxGroupToCategory[] $categoriesToGroups | |
54 | + * @property TaxGroup[] $taxGroupsByLevel | |
55 | + * * From language behavior * | |
56 | + * @property ProductLang $lang | |
57 | + * @property ProductLang[] $langs | |
58 | + * @property ProductLang $objectLang | |
59 | + * @property string $ownerKey | |
60 | + * @property string $langKey | |
61 | + * @property ProductLang[] $modelLangs | |
62 | + * @property bool $transactionStatus | |
63 | + * @method string getOwnerKey() | |
64 | + * @method void setOwnerKey( string $value ) | |
65 | + * @method string getLangKey() | |
66 | + * @method void setLangKey( string $value ) | |
67 | + * @method ActiveQuery getLangs() | |
68 | + * @method ActiveQuery getLang( integer $language_id ) | |
69 | + * @method ProductLang[] generateLangs() | |
70 | + * @method void loadLangs( Request $request ) | |
71 | + * @method bool linkLangs() | |
72 | + * @method bool saveLangs() | |
73 | + * @method bool getTransactionStatus() | |
74 | + * * End language behavior * | |
75 | + * * From multipleImage behavior | |
76 | + * @property ProductImage $image | |
77 | + * @property ProductImage[] $images | |
78 | + * @property array imagesConfig | |
79 | + * @method ActiveQuery getImage() | |
80 | + * @method ActiveQuery getImages() | |
81 | + * @method array getImagesConfig() | |
82 | + * @method array getImagesHTML( string $preset ) | |
83 | + * * End multipleImage behavior | |
84 | + */ | |
85 | + class Product extends ActiveRecord | |
86 | + { | |
87 | + | |
88 | + public $imagesUpload = []; | |
89 | + | |
90 | + /** | |
91 | + * @inheritdoc | |
92 | + */ | |
93 | + public function behaviors() | |
94 | + { | |
95 | + return [ | |
96 | + 'images' => [ | |
97 | + 'class' => SaveMultipleFileBehavior::className(), | |
98 | + 'name' => 'imagesUpload', | |
99 | + 'directory' => 'products', | |
100 | + 'column' => 'image', | |
101 | + 'links' => [ | |
102 | + 'id' => 'product_id', | |
103 | + ], | |
104 | + 'model' => ProductImage::className(), | |
105 | + ], | |
106 | + 'multipleImage' => [ | |
107 | + 'class' => MultipleImgBehavior::className(), | |
108 | + 'links' => [ | |
109 | + 'product_id' => 'id', | |
110 | + ], | |
111 | + 'conditions' => [ | |
112 | + 'product_variant_id' => null, | |
113 | + ], | |
114 | + 'model' => ProductImage::className(), | |
115 | + 'config' => [ | |
116 | + 'caption' => 'image', | |
117 | + 'delete_action' => '/product/manage/delete-image', | |
118 | + 'id' => 'id', | |
119 | + ], | |
120 | + ], | |
121 | + 'language' => [ | |
122 | + 'class' => LanguageBehavior::className(), | |
123 | + ], | |
124 | + 'defaultVariant' => DefaultVariantBehavior::className(), | |
125 | + ]; | |
126 | + } | |
127 | + | |
128 | + /** | |
129 | + * @inheritdoc | |
130 | + */ | |
131 | + public static function tableName() | |
132 | + { | |
133 | + return 'product'; | |
134 | + } | |
135 | + | |
136 | + /** | |
137 | + * @inheritdoc | |
138 | + */ | |
139 | + public function rules() | |
140 | + { | |
141 | + return [ | |
142 | + [ | |
143 | + [ 'brand_id' ], | |
144 | + 'integer', | |
145 | + ], | |
146 | + [ | |
147 | + [ | |
148 | + 'categories', | |
149 | + 'variants', | |
150 | + 'options', | |
151 | + 'imagesUpload', | |
152 | + ], | |
153 | + 'safe', | |
154 | + ], | |
155 | + [ | |
156 | + [ | |
157 | + 'video', | |
158 | + ], | |
159 | + 'safe', | |
160 | + ], | |
161 | + [ | |
162 | + [ | |
163 | + 'is_top', | |
164 | + 'is_new', | |
165 | + 'is_discount', | |
166 | + ], | |
167 | + 'boolean', | |
168 | + ], | |
169 | + ]; | |
170 | + } | |
171 | + | |
172 | + /** | |
173 | + * @inheritdoc | |
174 | + */ | |
175 | + public function attributeLabels() | |
176 | + { | |
177 | + return [ | |
178 | + 'id' => Yii::t('product', 'ID'), | |
179 | + 'brand_id' => Yii::t('product', 'Brand'), | |
180 | + 'categories' => Yii::t('product', 'Categories'), | |
181 | + 'category' => Yii::t('product', 'Category'), | |
182 | + 'image' => Yii::t('product', 'Image'), | |
183 | + 'images' => Yii::t('product', 'Images'), | |
184 | + 'video' => Yii::t('product', 'Video embeded'), | |
185 | + 'variants' => Yii::t('product', 'Variants'), | |
186 | + 'is_top' => Yii::t('product', 'Is top'), | |
187 | + 'is_new' => Yii::t('product', 'Is new'), | |
188 | + 'is_discount' => Yii::t('product', 'Is promo'), | |
189 | + ]; | |
190 | + } | |
191 | + | |
192 | + /** | |
193 | + * Get Brand query to current Product | |
194 | + * | |
195 | + * @return \yii\db\ActiveQuery | |
196 | + */ | |
197 | + public function getBrand() | |
198 | + { | |
199 | + return $this->hasOne(Brand::className(), [ 'id' => 'brand_id' ]); | |
200 | + } | |
201 | + | |
202 | + /** | |
203 | + * Get ProductVariant query to current Product | |
204 | + * | |
205 | + * @return \yii\db\ActiveQuery | |
206 | + */ | |
207 | + public function getVariant() | |
208 | + { | |
209 | + return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ]); | |
210 | + } | |
211 | + | |
212 | + /** | |
213 | + * Synonim of getVariant() | |
214 | + * | |
215 | + * @see Product::getVariant() | |
216 | + * @return \yii\db\ActiveQuery | |
217 | + */ | |
218 | + public function getProductVariant() | |
219 | + { | |
220 | + return $this->getVariant(); | |
221 | + } | |
222 | + | |
223 | + /** | |
224 | + * Get ProductVariants query to current Product | |
225 | + * | |
226 | + * @return \yii\db\ActiveQuery | |
227 | + */ | |
228 | + public function getVariants() | |
229 | + { | |
230 | + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]); | |
231 | + } | |
232 | + | |
233 | + /** | |
234 | + * Synonim of getVariants() | |
235 | + * | |
236 | + * @see Product::getVariants() | |
237 | + * @return \yii\db\ActiveQuery | |
238 | + */ | |
239 | + public function getProductVariants() | |
240 | + { | |
241 | + return $this->getVariant(); | |
242 | + } | |
243 | + | |
244 | + /** | |
245 | + * Get ProductVariant query fetching only available in stock to current Product | |
246 | + * | |
247 | + * @see Product::getVariant() | |
248 | + * @return \yii\db\ActiveQuery | |
249 | + */ | |
250 | + public function getEnabledVariant() | |
251 | + { | |
252 | + return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ]) | |
253 | + ->andWhere( | |
254 | + [ | |
255 | + '!=', | |
256 | + ProductVariant::tableName() . '.stock', | |
257 | + 0, | |
258 | + ] | |
259 | + ); | |
260 | + } | |
261 | + | |
262 | + /** | |
263 | + * Get ProductVariants query fetching only available in stock to current Product | |
264 | + * | |
265 | + * @see Product::getVariants() | |
266 | + * @return \yii\db\ActiveQuery | |
267 | + */ | |
268 | + public function getEnabledVariants() | |
269 | + { | |
270 | + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]) | |
271 | + ->andWhere( | |
272 | + [ | |
273 | + '!=', | |
274 | + ProductVariant::tableName() . '.stock', | |
275 | + 0, | |
276 | + ] | |
277 | + ); | |
278 | + } | |
279 | + | |
280 | + /** | |
281 | + * Get random ProductVariant price or 0 if not exist | |
282 | + * | |
283 | + * @param bool $exception Whether to throw exception if variant not exist | |
284 | + * | |
285 | + * @return float | |
286 | + * @throws \yii\web\NotFoundHttpException | |
287 | + */ | |
288 | + public function getVariantPrice(bool $exception = false): float | |
289 | + { | |
290 | + if (!empty( $this->variant )) { | |
291 | + return $this->variant->price; | |
292 | + } elseif ($exception) { | |
293 | + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got variants'); | |
294 | + } else { | |
295 | + return 0; | |
296 | + } | |
297 | + } | |
298 | + | |
299 | + /** | |
300 | + * Get random ProductVariant that in stock price or 0 or exception if not exist | |
301 | + * | |
302 | + * @param bool $exception Whether to throw exception if variant not exist | |
303 | + * | |
304 | + * @return float | |
305 | + * @throws \yii\web\NotFoundHttpException | |
306 | + */ | |
307 | + public function getEnabledVariantPrice(bool $exception = false): float | |
308 | + { | |
309 | + if (!empty( $this->enabledVariant )) { | |
310 | + return $this->enabledVariant->price; | |
311 | + } elseif ($exception) { | |
312 | + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got enabled variants'); | |
313 | + } else { | |
314 | + return 0; | |
315 | + } | |
316 | + } | |
317 | + | |
318 | + /** | |
319 | + * Get Product name concatenated with Brand name | |
320 | + * | |
321 | + * @return string | |
322 | + */ | |
323 | + public function getFullname():string | |
324 | + { | |
325 | + return empty( $this->brand ) ? $this->lang->title : $this->brand->lang->title . ' ' . $this->lang->title; | |
326 | + } | |
327 | + | |
328 | + /** | |
329 | + * Get Category query for current Product | |
330 | + * | |
331 | + * @return ActiveQuery | |
332 | + */ | |
333 | + public function getCategory() | |
334 | + { | |
335 | + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]) | |
336 | + ->viaTable('product_category', [ 'product_id' => 'id' ]); | |
337 | + } | |
338 | + | |
339 | + /** | |
340 | + * Get Categories query for current Product | |
341 | + * | |
342 | + * @return ActiveQuery | |
343 | + */ | |
344 | + public function getCategories() | |
345 | + { | |
346 | + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ]) | |
347 | + ->viaTable('product_category', [ 'product_id' => 'id' ]); | |
348 | + } | |
349 | + | |
350 | + /** | |
351 | + * @param bool $index | |
352 | + * | |
353 | + * @return array | |
354 | + */ | |
355 | + public function getCategoryNames(bool $index = false): array | |
356 | + { | |
357 | + if ($index) { | |
358 | + $result = ArrayHelper::map($this->categories, 'id', 'lang.title'); | |
359 | + } else { | |
360 | + $result = ArrayHelper::getColumn($this->categories, 'lang.title'); | |
361 | + } | |
362 | + return $result; | |
363 | + } | |
364 | + | |
365 | + /** | |
366 | + * Get ProductVariants query with lang, filters and image for current Product | |
367 | + * | |
368 | + * @return ActiveQuery | |
369 | + */ | |
370 | + public function getVariantsWithFilters() | |
371 | + { | |
372 | + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]) | |
373 | + ->joinWith('lang') | |
374 | + ->with( | |
375 | + [ | |
376 | + 'filters', | |
377 | + 'image', | |
378 | + ] | |
379 | + ); | |
380 | + } | |
381 | + | |
382 | + /** | |
383 | + * Get TaxOptions query for current Product | |
384 | + * | |
385 | + * @return ActiveQuery | |
386 | + */ | |
387 | + public function getOptions() | |
388 | + { | |
389 | + return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) | |
390 | + ->viaTable('product_option', [ 'product_id' => 'id' ]); | |
391 | + } | |
392 | + | |
393 | + /** | |
394 | + * Get TaxOptions query for current Product joined with TaxGroups | |
395 | + * | |
396 | + * @see Product::getOptions() | |
397 | + * @return ActiveQuery | |
398 | + */ | |
399 | + public function getFilters() | |
400 | + { | |
401 | + return $this->getOptions() | |
402 | + ->joinWith('taxGroup.lang') | |
403 | + ->joinWith('lang'); | |
404 | + } | |
405 | + | |
406 | + /** | |
407 | + * Get all TaxGroups for current Product filled with $customOptions that satisfy current Product | |
408 | + * | |
409 | + * @return TaxGroup[] | |
410 | + */ | |
411 | + public function getProperties(): array | |
412 | + { | |
413 | + $groups = $options = []; | |
414 | + foreach ($this->getOptions() | |
415 | + ->with('lang') | |
416 | + ->all() as $option) { | |
417 | + /** | |
418 | + * @var TaxOption $option | |
419 | + */ | |
420 | + $options[ $option[ 'tax_group_id' ] ][] = $option; | |
421 | + } | |
422 | + foreach (TaxGroup::find() | |
423 | + ->where([ 'id' => array_keys($options) ]) | |
424 | + ->with('lang') | |
425 | + ->all() as $group) { | |
426 | + /** | |
427 | + * @var TaxGroup $group | |
428 | + */ | |
429 | + if (!empty( $options[ $group->id ] )) { | |
430 | + $group->customOptions = $options[ $group->id ]; | |
431 | + $groups[] = $group; | |
432 | + } | |
433 | + } | |
434 | + return $groups; | |
435 | + } | |
436 | + | |
437 | + /** | |
438 | + * Get Stock query where current Product is in stock | |
439 | + * | |
440 | + * @return ActiveQuery | |
441 | + */ | |
442 | + public function getStocks() | |
443 | + { | |
444 | + return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ]) | |
445 | + ->via('productStocks'); | |
446 | + } | |
447 | + | |
448 | + /** | |
449 | + * Get ProductStocks query for current Product | |
450 | + * | |
451 | + * @return ActiveQuery | |
452 | + */ | |
453 | + public function getProductStocks() | |
454 | + { | |
455 | + return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]) | |
456 | + ->via('variants'); | |
457 | + } | |
458 | + | |
459 | + /** | |
460 | + * Get quantity of all ProductVariants for current Product | |
461 | + * | |
462 | + * @see Product::getProductStocks() | |
463 | + * @return int | |
464 | + */ | |
465 | + public function getQuantity():int | |
466 | + { | |
467 | + return $this->getProductStocks() | |
468 | + ->sum('quantity'); | |
469 | + } | |
470 | + | |
471 | + /** | |
472 | + * Override Categories and TaxOptions | |
473 | + * | |
474 | + * @inheritdoc | |
475 | + */ | |
476 | + public function afterSave($insert, $changedAttributes) | |
477 | + { | |
478 | + parent::afterSave($insert, $changedAttributes); | |
479 | + | |
480 | + if (!empty( $this->categories )) { | |
481 | + $categories = Category::findAll($this->categories); | |
482 | + $this->unlinkAll('categories', true); | |
483 | + foreach ($categories as $category) { | |
484 | + $this->link('categories', $category); | |
485 | + } | |
486 | + } | |
487 | + | |
488 | + if (!empty( $this->options )) { | |
489 | + $options = TaxOption::findAll($this->options); | |
490 | + $this->unlinkAll('options', true); | |
491 | + foreach ($options as $option) { | |
492 | + $this->link('options', $option); | |
493 | + } | |
494 | + } | |
495 | + } | |
496 | + | |
497 | + /** | |
498 | + * Recalculate rating for artboxcomment module | |
499 | + * | |
500 | + * @todo Rewrite with behavior | |
501 | + * @return bool | |
502 | + */ | |
503 | + public function recalculateRating():bool | |
504 | + { | |
505 | + /** | |
506 | + * @var ProductToRating $averageRating | |
507 | + */ | |
508 | + $average = $this->getComments() | |
509 | + ->joinWith('rating') | |
510 | + ->select([ 'average' => 'avg(artbox_comment_rating.value)::float' ]) | |
511 | + ->scalar(); | |
512 | + if (!$average) { | |
513 | + $average = 0; | |
514 | + } | |
515 | + $averageRating = $this->averageRating; | |
516 | + if (!empty( $averageRating )) { | |
517 | + $averageRating->value = $average; | |
518 | + } else { | |
519 | + $averageRating = new ProductToRating( | |
520 | + [ | |
521 | + 'product_id' => $this->id, | |
522 | + 'value' => $average, | |
523 | + ] | |
524 | + ); | |
525 | + } | |
526 | + if ($averageRating->save()) { | |
527 | + return true; | |
528 | + } else { | |
529 | + return false; | |
530 | + } | |
531 | + } | |
532 | + | |
533 | + /** | |
534 | + * Get CommmentModel query for artboxcomment module | |
535 | + * | |
536 | + * @todo Rewrite with behavior | |
537 | + * @return ActiveQuery | |
538 | + */ | |
539 | + public function getComments() | |
540 | + { | |
541 | + return $this->hasMany(CommentModel::className(), [ 'entity_id' => 'id' ]) | |
542 | + ->where( | |
543 | + [ | |
544 | + 'artbox_comment.entity' => self::className(), | |
545 | + 'artbox_comment.status' => CommentModel::STATUS_ACTIVE, | |
546 | + 'artbox_comment.artbox_comment_pid' => null, | |
547 | + ] | |
548 | + ); | |
549 | + } | |
550 | + | |
551 | + /** | |
552 | + * Get ProductToRating query in order to get average rating for current Product | |
553 | + * | |
554 | + * @return \yii\db\ActiveQuery | |
555 | + */ | |
556 | + public function getAverageRating() | |
557 | + { | |
558 | + return $this->hasOne(ProductToRating::className(), [ 'product_id' => 'id' ]); | |
559 | + } | |
560 | + | |
561 | + /** | |
562 | + * Get TaxGroupToCategories query via product_category table | |
563 | + * | |
564 | + * @return ActiveQuery | |
565 | + */ | |
566 | + public function getCategoriesToGroups() | |
567 | + { | |
568 | + return $this->hasMany(TaxGroupToCategory::className(), [ 'category_id' => 'category_id' ]) | |
569 | + ->viaTable('product_category', [ 'product_id' => 'id' ]); | |
570 | + } | |
571 | + | |
572 | + /** | |
573 | + * Get TaxGroups query for current Product according to level | |
574 | + * * 0 - Product Tax Groups | |
575 | + * * 1 - ProductVariant Tax Groups | |
576 | + * | |
577 | + * @param int $level | |
578 | + * | |
579 | + * @return ActiveQuery | |
580 | + * @throws InvalidParamException | |
581 | + */ | |
582 | + public function getTaxGroupsByLevel(int $level = 0) | |
583 | + { | |
584 | + if ($level !== 0 && $level !== 1) { | |
585 | + throw new InvalidParamException( | |
586 | + 'Level must be 0 for Product Tax Groups or 1 for Product Variant Tax Groups' | |
587 | + ); | |
588 | + } | |
589 | + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) | |
590 | + ->via('categoriesToGroups') | |
591 | + ->where([ 'level' => $level ]) | |
592 | + ->distinct(); | |
593 | + } | |
594 | + | |
595 | + /** | |
596 | + * Setter for Categories | |
597 | + * | |
598 | + * @param array $values | |
599 | + */ | |
600 | + public function setCategories($values) | |
601 | + { | |
602 | + $this->categories = $values; | |
603 | + } | |
604 | + | |
605 | + /** | |
606 | + * Setter for Options | |
607 | + * | |
608 | + * @param array $values | |
609 | + */ | |
610 | + public function setOptions($values) | |
611 | + { | |
612 | + $this->options = $values; | |
613 | + } | |
614 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductCategory.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use Yii; | |
6 | + use yii\db\ActiveRecord; | |
7 | + | |
8 | + /** | |
9 | + * This is the model class for table "{{%product_category}}". | |
10 | + * | |
11 | + * @property integer $product_id | |
12 | + * @property integer $category_id | |
13 | + */ | |
14 | + class ProductCategory extends ActiveRecord | |
15 | + { | |
16 | + /** | |
17 | + * @inheritdoc | |
18 | + */ | |
19 | + public static function tableName() | |
20 | + { | |
21 | + return 'product_category'; | |
22 | + } | |
23 | + | |
24 | + /** | |
25 | + * @inheritdoc | |
26 | + */ | |
27 | + public function rules() | |
28 | + { | |
29 | + return [ | |
30 | + [ | |
31 | + [ | |
32 | + 'product_id', | |
33 | + 'category_id', | |
34 | + ], | |
35 | + 'integer', | |
36 | + ], | |
37 | + [ | |
38 | + [ 'category_id' ], | |
39 | + 'exist', | |
40 | + 'skipOnError' => true, | |
41 | + 'targetClass' => Category::className(), | |
42 | + 'targetAttribute' => [ 'category_id' => 'id' ], | |
43 | + ], | |
44 | + [ | |
45 | + [ 'product_id' ], | |
46 | + 'exist', | |
47 | + 'skipOnError' => true, | |
48 | + 'targetClass' => Product::className(), | |
49 | + 'targetAttribute' => [ 'product_id' => 'id' ], | |
50 | + ], | |
51 | + ]; | |
52 | + } | |
53 | + | |
54 | + /** | |
55 | + * @inheritdoc | |
56 | + */ | |
57 | + public function attributeLabels() | |
58 | + { | |
59 | + return [ | |
60 | + 'product_id' => Yii::t('product', 'Product'), | |
61 | + 'category_id' => Yii::t('product', 'Category'), | |
62 | + ]; | |
63 | + } | |
64 | + | |
65 | + public function getCategory() | |
66 | + { | |
67 | + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]); | |
68 | + } | |
69 | + | |
70 | + public function getProduct() | |
71 | + { | |
72 | + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); | |
73 | + } | |
74 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductImage.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\ImageBehavior; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "product_image". | |
11 | + * | |
12 | + * @property integer $id | |
13 | + * @property integer $product_id | |
14 | + * @property integer $product_variant_id | |
15 | + * @property string $image | |
16 | + * @property string $alt | |
17 | + * @property string $title | |
18 | + * @property Product $product | |
19 | + * @property ProductVariant $productVariant | |
20 | + */ | |
21 | + class ProductImage extends ActiveRecord | |
22 | + { | |
23 | + | |
24 | + /** | |
25 | + * @inheritdoc | |
26 | + */ | |
27 | + public static function tableName() | |
28 | + { | |
29 | + return 'product_image'; | |
30 | + } | |
31 | + | |
32 | + public function behaviors() | |
33 | + { | |
34 | + return [ | |
35 | + [ | |
36 | + 'class' => ImageBehavior::className(), | |
37 | + 'link' => 'image', | |
38 | + 'directory' => 'products', | |
39 | + ], | |
40 | + ]; | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * @inheritdoc | |
45 | + */ | |
46 | + public function rules() | |
47 | + { | |
48 | + return [ | |
49 | + [ | |
50 | + [ 'product_id' ], | |
51 | + 'required', | |
52 | + ], | |
53 | + [ | |
54 | + [ | |
55 | + 'id', | |
56 | + 'product_id', | |
57 | + 'product_variant_id', | |
58 | + ], | |
59 | + 'integer', | |
60 | + ], | |
61 | + [ | |
62 | + [ | |
63 | + 'alt', | |
64 | + 'title', | |
65 | + 'image', | |
66 | + ], | |
67 | + 'string', | |
68 | + 'max' => 255, | |
69 | + ], | |
70 | + [ | |
71 | + [ 'product_id' ], | |
72 | + 'exist', | |
73 | + 'skipOnError' => true, | |
74 | + 'targetClass' => Product::className(), | |
75 | + 'targetAttribute' => [ 'product_id' => 'id' ], | |
76 | + ], | |
77 | + [ | |
78 | + [ 'product_variant_id' ], | |
79 | + 'exist', | |
80 | + 'skipOnError' => true, | |
81 | + 'targetClass' => ProductVariant::className(), | |
82 | + 'targetAttribute' => [ 'product_variant_id' => 'id' ], | |
83 | + ], | |
84 | + ]; | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * @inheritdoc | |
89 | + */ | |
90 | + public function attributeLabels() | |
91 | + { | |
92 | + return [ | |
93 | + 'id' => Yii::t('product', 'Product Image ID'), | |
94 | + 'product_id' => Yii::t('product', 'Product ID'), | |
95 | + 'product_variant_id' => Yii::t('product', 'Product Variant ID'), | |
96 | + 'product' => Yii::t('product', 'Product'), | |
97 | + 'product_variant' => Yii::t('product', 'Product Variant'), | |
98 | + 'image' => Yii::t('product', 'Image'), | |
99 | + 'alt' => Yii::t('product', 'Alt'), | |
100 | + 'title' => Yii::t('product', 'Title'), | |
101 | + ]; | |
102 | + } | |
103 | + | |
104 | + /** | |
105 | + * @return \yii\db\ActiveQuery | |
106 | + */ | |
107 | + public function getProduct() | |
108 | + { | |
109 | + $return = $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); | |
110 | + return $return; | |
111 | + } | |
112 | + | |
113 | + /** | |
114 | + * @return \yii\db\ActiveQuery | |
115 | + */ | |
116 | + public function getProductVariant() | |
117 | + { | |
118 | + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]); | |
119 | + } | |
120 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "product_lang". | |
11 | + * @property integer $product_id | |
12 | + * @property integer $language_id | |
13 | + * @property string $title | |
14 | + * @property string $description | |
15 | + * @property string $alias | |
16 | + * @property Language $language | |
17 | + * @property Product $product | |
18 | + */ | |
19 | + class ProductLang extends ActiveRecord | |
20 | + { | |
21 | + | |
22 | + public static function primaryKey() | |
23 | + { | |
24 | + return [ | |
25 | + 'product_id', | |
26 | + 'language_id', | |
27 | + ]; | |
28 | + } | |
29 | + | |
30 | + /** | |
31 | + * @inheritdoc | |
32 | + */ | |
33 | + public static function tableName() | |
34 | + { | |
35 | + return 'product_lang'; | |
36 | + } | |
37 | + | |
38 | + public function behaviors() | |
39 | + { | |
40 | + return [ | |
41 | + 'slug' => [ | |
42 | + 'class' => 'common\behaviors\Slug', | |
43 | + ], | |
44 | + ]; | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * @inheritdoc | |
49 | + */ | |
50 | + public function rules() | |
51 | + { | |
52 | + return [ | |
53 | + [ | |
54 | + [ 'title' ], | |
55 | + 'required', | |
56 | + ], | |
57 | + [ | |
58 | + [ 'description' ], | |
59 | + 'string', | |
60 | + ], | |
61 | + [ | |
62 | + [ | |
63 | + 'title', | |
64 | + 'alias', | |
65 | + ], | |
66 | + 'string', | |
67 | + 'max' => 255, | |
68 | + ], | |
69 | + [ | |
70 | + [ | |
71 | + 'product_id', | |
72 | + 'language_id', | |
73 | + ], | |
74 | + 'unique', | |
75 | + 'targetAttribute' => [ | |
76 | + 'product_id', | |
77 | + 'language_id', | |
78 | + ], | |
79 | + 'message' => 'The combination of Product ID and Language ID has already been taken.', | |
80 | + ], | |
81 | + [ | |
82 | + [ 'language_id' ], | |
83 | + 'exist', | |
84 | + 'skipOnError' => true, | |
85 | + 'targetClass' => Language::className(), | |
86 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
87 | + ], | |
88 | + [ | |
89 | + [ 'product_id' ], | |
90 | + 'exist', | |
91 | + 'skipOnError' => true, | |
92 | + 'targetClass' => Product::className(), | |
93 | + 'targetAttribute' => [ 'product_id' => 'id' ], | |
94 | + ], | |
95 | + ]; | |
96 | + } | |
97 | + | |
98 | + /** | |
99 | + * @inheritdoc | |
100 | + */ | |
101 | + public function attributeLabels() | |
102 | + { | |
103 | + return [ | |
104 | + 'product_id' => Yii::t('app', 'Product ID'), | |
105 | + 'language_id' => Yii::t('app', 'Language ID'), | |
106 | + 'title' => Yii::t('app', 'Name'), | |
107 | + 'description' => Yii::t('app', 'Description'), | |
108 | + 'alias' => Yii::t('app', 'Alias'), | |
109 | + ]; | |
110 | + } | |
111 | + | |
112 | + /** | |
113 | + * @return \yii\db\ActiveQuery | |
114 | + */ | |
115 | + public function getLanguage() | |
116 | + { | |
117 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
118 | + } | |
119 | + | |
120 | + /** | |
121 | + * @return \yii\db\ActiveQuery | |
122 | + */ | |
123 | + public function getProduct() | |
124 | + { | |
125 | + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); | |
126 | + } | |
127 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductOption.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\TaxOption; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "product_option". | |
11 | + * @property integer $product_id | |
12 | + * @property integer $option_id | |
13 | + * @property Product $product | |
14 | + * @property TaxOption $option | |
15 | + */ | |
16 | + class ProductOption extends ActiveRecord | |
17 | + { | |
18 | + | |
19 | + /** | |
20 | + * @inheritdoc | |
21 | + */ | |
22 | + public static function tableName() | |
23 | + { | |
24 | + return 'product_option'; | |
25 | + } | |
26 | + | |
27 | + /** | |
28 | + * @inheritdoc | |
29 | + */ | |
30 | + public function rules() | |
31 | + { | |
32 | + return [ | |
33 | + [ | |
34 | + [ | |
35 | + 'product_id', | |
36 | + 'option_id', | |
37 | + ], | |
38 | + 'required', | |
39 | + ], | |
40 | + [ | |
41 | + [ | |
42 | + 'product_id', | |
43 | + 'option_id', | |
44 | + ], | |
45 | + 'integer', | |
46 | + ], | |
47 | + [ | |
48 | + [ 'product_id' ], | |
49 | + 'exist', | |
50 | + 'skipOnError' => true, | |
51 | + 'targetClass' => Product::className(), | |
52 | + 'targetAttribute' => [ 'product_id' => 'id' ], | |
53 | + ], | |
54 | + [ | |
55 | + [ 'option_id' ], | |
56 | + 'exist', | |
57 | + 'skipOnError' => true, | |
58 | + 'targetClass' => TaxOption::className(), | |
59 | + 'targetAttribute' => [ 'option_id' => 'id' ], | |
60 | + ], | |
61 | + ]; | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * @inheritdoc | |
66 | + */ | |
67 | + public function attributeLabels() | |
68 | + { | |
69 | + return [ | |
70 | + 'product_id' => Yii::t('product', 'Product ID'), | |
71 | + 'option_id' => Yii::t('product', 'Option ID'), | |
72 | + ]; | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * @return \yii\db\ActiveQuery | |
77 | + */ | |
78 | + public function getProduct() | |
79 | + { | |
80 | + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @return \yii\db\ActiveQuery | |
85 | + */ | |
86 | + public function getOption() | |
87 | + { | |
88 | + return $this->hasOne(TaxOption::className(), [ 'id' => 'option_id' ]); | |
89 | + } | |
90 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + use yii\db\ActiveQuery; | |
8 | + | |
9 | + /** | |
10 | + * ProductSearch represents the model behind the search form about | |
11 | + * `artweb\artbox\ecommerce\models\Product`. | |
12 | + */ | |
13 | + class ProductSearch extends Product | |
14 | + { | |
15 | + | |
16 | + public $categoryId; | |
17 | + | |
18 | + public $productName; | |
19 | + | |
20 | + public $variantCount; | |
21 | + | |
22 | + public function behaviors() | |
23 | + { | |
24 | + $behaviors = parent::behaviors(); | |
25 | + if (isset( $behaviors[ 'language' ] )) { | |
26 | + unset( $behaviors[ 'language' ] ); | |
27 | + } | |
28 | + return $behaviors; | |
29 | + } | |
30 | + | |
31 | + /** | |
32 | + * @inheritdoc | |
33 | + */ | |
34 | + public function rules() | |
35 | + { | |
36 | + return [ | |
37 | + [ | |
38 | + [ | |
39 | + 'productName', | |
40 | + ], | |
41 | + 'safe', | |
42 | + ], | |
43 | + [ | |
44 | + [ | |
45 | + 'brand_id', | |
46 | + 'id', | |
47 | + 'categoryId', | |
48 | + ], | |
49 | + 'integer', | |
50 | + ], | |
51 | + [ | |
52 | + [ | |
53 | + 'is_top', | |
54 | + 'is_new', | |
55 | + 'is_discount', | |
56 | + ], | |
57 | + 'boolean', | |
58 | + ], | |
59 | + ]; | |
60 | + } | |
61 | + | |
62 | + public function attributeLabels() | |
63 | + { | |
64 | + $labels = parent::attributeLabels(); | |
65 | + $new_labels = [ | |
66 | + 'categoryId' => 'Category ID', | |
67 | + 'brand_id' => 'Brand ID', | |
68 | + 'productName' => 'Product name', | |
69 | + 'variantCount' => 'Variant count', | |
70 | + ]; | |
71 | + return array_merge($labels, $new_labels); | |
72 | + } | |
73 | + | |
74 | + /** | |
75 | + * @inheritdoc | |
76 | + */ | |
77 | + public function scenarios() | |
78 | + { | |
79 | + // bypass scenarios() implementation in the parent class | |
80 | + return Model::scenarios(); | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * Creates data provider instance with search query applied | |
85 | + * | |
86 | + * @param array $params | |
87 | + * | |
88 | + * @return ActiveDataProvider | |
89 | + */ | |
90 | + public function search($params) | |
91 | + { | |
92 | + $query = Product::find(); | |
93 | + $query->select( | |
94 | + [ | |
95 | + 'product.*', | |
96 | + ] | |
97 | + ); | |
98 | + | |
99 | + $query->joinWith( | |
100 | + [ | |
101 | + 'categories', | |
102 | + 'lang', | |
103 | + ] | |
104 | + ) | |
105 | + ->joinWith( | |
106 | + [ | |
107 | + 'brand' => function ($query) { | |
108 | + /** | |
109 | + * @var ActiveQuery $query | |
110 | + */ | |
111 | + $query->joinWith('lang'); | |
112 | + }, | |
113 | + ] | |
114 | + ) | |
115 | + ->joinWith('variants'); | |
116 | + | |
117 | + $query->groupBy( | |
118 | + [ | |
119 | + 'product.id', | |
120 | + 'product_variant.id', | |
121 | + ] | |
122 | + ); | |
123 | + | |
124 | + $dataProvider = new ActiveDataProvider( | |
125 | + [ | |
126 | + 'query' => $query, | |
127 | + ] | |
128 | + ); | |
129 | + | |
130 | + $dataProvider->setSort( | |
131 | + [ | |
132 | + 'attributes' => [ | |
133 | + 'id', | |
134 | + 'productName' => [ | |
135 | + 'asc' => [ 'product_lang.title' => SORT_ASC ], | |
136 | + 'desc' => [ 'product_lang.title' => SORT_DESC ], | |
137 | + ], | |
138 | + 'brand_id' => [ | |
139 | + 'asc' => [ 'brand_lang.title' => SORT_ASC ], | |
140 | + 'desc' => [ 'brand_lang.title' => SORT_DESC ], | |
141 | + ], | |
142 | + ], | |
143 | + ] | |
144 | + ); | |
145 | + | |
146 | + $this->load($params); | |
147 | + | |
148 | + if (!$this->validate()) { | |
149 | + // uncomment the following line if you do not want to return any records when validation fails | |
150 | + // $query->where('0=1'); | |
151 | + return $dataProvider; | |
152 | + } | |
153 | + | |
154 | + if (isset( $this->is_top )) { | |
155 | + $query->andWhere( | |
156 | + [ | |
157 | + 'is_top' => (bool) $this->is_top, | |
158 | + ] | |
159 | + ); | |
160 | + } | |
161 | + if (isset( $this->is_new )) { | |
162 | + $query->andWhere( | |
163 | + [ | |
164 | + 'is_new' => (bool) $this->is_new, | |
165 | + ] | |
166 | + ); | |
167 | + } | |
168 | + if (isset( $this->is_discount )) { | |
169 | + $query->andWhere( | |
170 | + [ | |
171 | + 'is_discount' => (bool) $this->is_discount, | |
172 | + ] | |
173 | + ); | |
174 | + } | |
175 | + $query->andFilterWhere( | |
176 | + [ | |
177 | + 'product.brand_id' => $this->brand_id, | |
178 | + 'product.id' => $this->id, | |
179 | + 'product_category.category_id' => $this->categoryId, | |
180 | + ] | |
181 | + ); | |
182 | + $query->andFilterWhere( | |
183 | + [ | |
184 | + 'like', | |
185 | + 'product_lang.title', | |
186 | + $this->productName, | |
187 | + ] | |
188 | + ); | |
189 | + | |
190 | + return $dataProvider; | |
191 | + } | |
192 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductStock.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\db\ActiveRecord; | |
6 | + | |
7 | + /** | |
8 | + * This is the model class for table "product_stock". | |
9 | + * | |
10 | + * @property integer $stock_id | |
11 | + * @property integer $quantity | |
12 | + * @property integer $product_variant_id | |
13 | + * @property Product $product | |
14 | + * @property ProductVariant $productVariant | |
15 | + * @property Stock $stock | |
16 | + * @property string $title | |
17 | + */ | |
18 | + class ProductStock extends ActiveRecord | |
19 | + { | |
20 | + protected $title; | |
21 | + /** | |
22 | + * @inheritdoc | |
23 | + */ | |
24 | + public static function tableName() | |
25 | + { | |
26 | + return 'product_stock'; | |
27 | + } | |
28 | + | |
29 | + /** | |
30 | + * @inheritdoc | |
31 | + */ | |
32 | + public function rules() | |
33 | + { | |
34 | + return [ | |
35 | + [ | |
36 | + [ | |
37 | + 'stock_id', | |
38 | + 'quantity', | |
39 | + 'product_variant_id', | |
40 | + ], | |
41 | + 'integer', | |
42 | + ], | |
43 | + [ | |
44 | + [ 'title' ], | |
45 | + 'required', | |
46 | + ], | |
47 | + [ | |
48 | + [ 'product_variant_id' ], | |
49 | + 'exist', | |
50 | + 'skipOnError' => true, | |
51 | + 'targetClass' => ProductVariant::className(), | |
52 | + 'targetAttribute' => [ 'product_variant_id' => 'id' ], | |
53 | + ], | |
54 | + [ | |
55 | + [ 'stock_id' ], | |
56 | + 'exist', | |
57 | + 'skipOnError' => true, | |
58 | + 'targetClass' => Stock::className(), | |
59 | + 'targetAttribute' => [ 'stock_id' => 'id' ], | |
60 | + ], | |
61 | + ]; | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * @inheritdoc | |
66 | + */ | |
67 | + public function attributeLabels() | |
68 | + { | |
69 | + return [ | |
70 | + 'stock_id' => 'Stock ID', | |
71 | + 'quantity' => 'Количество', | |
72 | + 'product_variant_id' => 'Product Variant ID', | |
73 | + 'title' => "Название", | |
74 | + ]; | |
75 | + } | |
76 | + | |
77 | + /** | |
78 | + * @return \yii\db\ActiveQuery | |
79 | + */ | |
80 | + public function getProduct() | |
81 | + { | |
82 | + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]) | |
83 | + ->via('variants'); | |
84 | + } | |
85 | + | |
86 | + /** | |
87 | + * @return \yii\db\ActiveQuery | |
88 | + */ | |
89 | + public function getProductVariant() | |
90 | + { | |
91 | + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]); | |
92 | + } | |
93 | + | |
94 | + /** | |
95 | + * Get Stock title, tries to get from Stock lang | |
96 | + * | |
97 | + * @return string | |
98 | + */ | |
99 | + public function getTitle(): string | |
100 | + { | |
101 | + if (!empty( $this->title )) { | |
102 | + return $this->title; | |
103 | + } elseif (!empty( $this->stock )) { | |
104 | + return $this->stock->lang->title; | |
105 | + } else { | |
106 | + return ''; | |
107 | + } | |
108 | + } | |
109 | + | |
110 | + /** | |
111 | + * Set Stock title, will be saved to Stock table | |
112 | + * | |
113 | + * @param mixed $value | |
114 | + */ | |
115 | + public function setTitle(string $value) | |
116 | + { | |
117 | + $this->title = $value; | |
118 | + } | |
119 | + | |
120 | + /** | |
121 | + * @return \yii\db\ActiveQuery | |
122 | + */ | |
123 | + public function getStock() | |
124 | + { | |
125 | + return $this->hasOne(Stock::className(), [ 'id' => 'stock_id' ]); | |
126 | + } | |
127 | + | |
128 | + /** | |
129 | + * @inheritdoc | |
130 | + */ | |
131 | + public static function primaryKey() | |
132 | + { | |
133 | + return [ | |
134 | + "stock_id", | |
135 | + "product_variant_id", | |
136 | + ]; | |
137 | + } | |
138 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductUnit.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\behaviors\LanguageBehavior; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveQuery; | |
8 | + use yii\db\ActiveRecord; | |
9 | + use yii\web\Request; | |
10 | + | |
11 | + /** | |
12 | + * This is the model class for table "product_unit". | |
13 | + * | |
14 | + * @property integer $id | |
15 | + * @property boolean $is_default | |
16 | + * @property Category[] $categories | |
17 | + * @property ProductVariant[] $productVariants | |
18 | + * * From language behavior * | |
19 | + * @property ProductUnitLang $lang | |
20 | + * @property ProductUnitLang[] $langs | |
21 | + * @property ProductUnitLang $objectLang | |
22 | + * @property string $ownerKey | |
23 | + * @property string $langKey | |
24 | + * @property ProductUnitLang[] $modelLangs | |
25 | + * @property bool $transactionStatus | |
26 | + * @method string getOwnerKey() | |
27 | + * @method void setOwnerKey( string $value ) | |
28 | + * @method string getLangKey() | |
29 | + * @method void setLangKey( string $value ) | |
30 | + * @method ActiveQuery getLangs() | |
31 | + * @method ActiveQuery getLang( integer $language_id ) | |
32 | + * @method ProductUnitLang[] generateLangs() | |
33 | + * @method void loadLangs( Request $request ) | |
34 | + * @method bool linkLangs() | |
35 | + * @method bool saveLangs() | |
36 | + * @method bool getTransactionStatus() | |
37 | + * * End language behavior * | |
38 | + */ | |
39 | + class ProductUnit extends ActiveRecord | |
40 | + { | |
41 | + | |
42 | + /** | |
43 | + * @inheritdoc | |
44 | + */ | |
45 | + public static function tableName() | |
46 | + { | |
47 | + return 'product_unit'; | |
48 | + } | |
49 | + | |
50 | + public function behaviors() | |
51 | + { | |
52 | + return [ | |
53 | + 'language' => [ | |
54 | + 'class' => LanguageBehavior::className(), | |
55 | + ], | |
56 | + ]; | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * @inheritdoc | |
61 | + */ | |
62 | + public function rules() | |
63 | + { | |
64 | + return [ | |
65 | + [ | |
66 | + [ 'is_default' ], | |
67 | + 'boolean', | |
68 | + ], | |
69 | + ]; | |
70 | + } | |
71 | + | |
72 | + /** | |
73 | + * @inheritdoc | |
74 | + */ | |
75 | + public function attributeLabels() | |
76 | + { | |
77 | + return [ | |
78 | + 'id' => Yii::t('product', 'Product Unit ID'), | |
79 | + 'is_default' => Yii::t('product', 'Is Default'), | |
80 | + ]; | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @return \yii\db\ActiveQuery | |
85 | + */ | |
86 | + public function getCategories() | |
87 | + { | |
88 | + return $this->hasMany(Category::className(), [ 'product_unit_id' => 'id' ]); | |
89 | + } | |
90 | + | |
91 | + /** | |
92 | + * @return \yii\db\ActiveQuery | |
93 | + */ | |
94 | + public function getProductVariants() | |
95 | + { | |
96 | + return $this->hasMany(ProductVariant::className(), [ 'product_unit_id' => 'id' ]); | |
97 | + } | |
98 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductUnitLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "product_unit_lang". | |
11 | + * | |
12 | + * @property integer $product_unit_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $title | |
15 | + * @property string $short | |
16 | + * @property Language $language | |
17 | + * @property ProductUnit $productUnit | |
18 | + */ | |
19 | + class ProductUnitLang extends ActiveRecord | |
20 | + { | |
21 | + | |
22 | + public static function primaryKey() | |
23 | + { | |
24 | + return [ | |
25 | + 'product_unit_id', | |
26 | + 'language_id', | |
27 | + ]; | |
28 | + } | |
29 | + | |
30 | + /** | |
31 | + * @inheritdoc | |
32 | + */ | |
33 | + public static function tableName() | |
34 | + { | |
35 | + return 'product_unit_lang'; | |
36 | + } | |
37 | + | |
38 | + /** | |
39 | + * @inheritdoc | |
40 | + */ | |
41 | + public function rules() | |
42 | + { | |
43 | + return [ | |
44 | + [ | |
45 | + [ 'title' ], | |
46 | + 'required', | |
47 | + ], | |
48 | + [ | |
49 | + [ | |
50 | + 'title', | |
51 | + 'short', | |
52 | + ], | |
53 | + 'string', | |
54 | + 'max' => 255, | |
55 | + ], | |
56 | + [ | |
57 | + [ | |
58 | + 'product_unit_id', | |
59 | + 'language_id', | |
60 | + ], | |
61 | + 'unique', | |
62 | + 'targetAttribute' => [ | |
63 | + 'product_unit_id', | |
64 | + 'language_id', | |
65 | + ], | |
66 | + 'message' => 'The combination of Product Unit ID and Language ID has already been taken.', | |
67 | + ], | |
68 | + [ | |
69 | + [ 'language_id' ], | |
70 | + 'exist', | |
71 | + 'skipOnError' => true, | |
72 | + 'targetClass' => Language::className(), | |
73 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
74 | + ], | |
75 | + [ | |
76 | + [ 'product_unit_id' ], | |
77 | + 'exist', | |
78 | + 'skipOnError' => true, | |
79 | + 'targetClass' => ProductUnit::className(), | |
80 | + 'targetAttribute' => [ 'product_unit_id' => 'id' ], | |
81 | + ], | |
82 | + ]; | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * @inheritdoc | |
87 | + */ | |
88 | + public function attributeLabels() | |
89 | + { | |
90 | + return [ | |
91 | + 'product_unit_id' => Yii::t('app', 'Product Unit ID'), | |
92 | + 'language_id' => Yii::t('app', 'Language ID'), | |
93 | + 'title' => Yii::t('app', 'Name'), | |
94 | + 'short' => Yii::t('app', 'Short'), | |
95 | + ]; | |
96 | + } | |
97 | + | |
98 | + /** | |
99 | + * @return \yii\db\ActiveQuery | |
100 | + */ | |
101 | + public function getLanguage() | |
102 | + { | |
103 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
104 | + } | |
105 | + | |
106 | + /** | |
107 | + * @return \yii\db\ActiveQuery | |
108 | + */ | |
109 | + public function getProductUnit() | |
110 | + { | |
111 | + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]); | |
112 | + } | |
113 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductUnitSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * ProductUnitSearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\ProductUnit`. | |
11 | + */ | |
12 | + class ProductUnitSearch extends ProductUnit | |
13 | + { | |
14 | + | |
15 | + public $title; | |
16 | + | |
17 | + public function behaviors() | |
18 | + { | |
19 | + return []; | |
20 | + } | |
21 | + | |
22 | + public function attributeLabels() | |
23 | + { | |
24 | + $labels = parent::attributeLabels(); | |
25 | + $new_labels = [ | |
26 | + 'title' => \Yii::t('product', 'Product Unit Name'), | |
27 | + ]; | |
28 | + return array_merge($labels, $new_labels); | |
29 | + } | |
30 | + | |
31 | + /** | |
32 | + * @inheritdoc | |
33 | + */ | |
34 | + public function rules() | |
35 | + { | |
36 | + return [ | |
37 | + [ | |
38 | + [ 'title' ], | |
39 | + 'safe', | |
40 | + ], | |
41 | + [ | |
42 | + [ 'id' ], | |
43 | + 'integer', | |
44 | + ], | |
45 | + [ | |
46 | + [ 'is_default' ], | |
47 | + 'boolean', | |
48 | + ], | |
49 | + ]; | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * @inheritdoc | |
54 | + */ | |
55 | + public function scenarios() | |
56 | + { | |
57 | + // bypass scenarios() implementation in the parent class | |
58 | + return Model::scenarios(); | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * Creates data provider instance with search query applied | |
63 | + * | |
64 | + * @param array $params | |
65 | + * | |
66 | + * @return ActiveDataProvider | |
67 | + */ | |
68 | + public function search($params) | |
69 | + { | |
70 | + $query = ProductUnit::find() | |
71 | + ->joinWith('lang'); | |
72 | + | |
73 | + // add conditions that should always apply here | |
74 | + | |
75 | + $dataProvider = new ActiveDataProvider( | |
76 | + [ | |
77 | + 'query' => $query, | |
78 | + 'sort' => [ | |
79 | + 'attributes' => [ | |
80 | + 'id', | |
81 | + 'is_defaut', | |
82 | + 'title' => [ | |
83 | + 'asc' => [ 'product_unit_lang.title' => SORT_ASC ], | |
84 | + 'desc' => [ 'product_unit_lang.title' => SORT_DESC ], | |
85 | + ], | |
86 | + ], | |
87 | + ], | |
88 | + ] | |
89 | + ); | |
90 | + | |
91 | + $this->load($params); | |
92 | + | |
93 | + if (!$this->validate()) { | |
94 | + // uncomment the following line if you do not want to return any records when validation fails | |
95 | + // $query->where('0=1'); | |
96 | + return $dataProvider; | |
97 | + } | |
98 | + | |
99 | + // grid filtering conditions | |
100 | + $query->andFilterWhere( | |
101 | + [ | |
102 | + 'id' => $this->id, | |
103 | + 'is_default' => $this->is_default, | |
104 | + ] | |
105 | + ) | |
106 | + ->andFilterWhere( | |
107 | + [ | |
108 | + 'ilike', | |
109 | + 'product_unit_lang.title', | |
110 | + $this->title, | |
111 | + ] | |
112 | + ); | |
113 | + | |
114 | + return $dataProvider; | |
115 | + } | |
116 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductVariant.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\MultipleImgBehavior; | |
6 | + use common\behaviors\SaveMultipleFileBehavior; | |
7 | + use common\modules\language\behaviors\LanguageBehavior; | |
8 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
9 | + use artweb\artbox\ecommerce\models\TaxOption; | |
10 | + use Yii; | |
11 | + use yii\base\InvalidParamException; | |
12 | + use yii\db\ActiveQuery; | |
13 | + use yii\db\ActiveRecord; | |
14 | + use yii\web\Request; | |
15 | + | |
16 | + /** | |
17 | + * This is the model class for table "product_variant". | |
18 | + * | |
19 | + * @property integer $id | |
20 | + * @property integer $product_id | |
21 | + * @property integer $remote_id | |
22 | + * @property string $sku | |
23 | + * @property double $price | |
24 | + * @property double $price_old | |
25 | + * @property double $stock | |
26 | + * @property integer $product_unit_id | |
27 | + * @property string $fullname | |
28 | + * @property TaxOption[] $options | |
29 | + * @property ProductUnit $productUnit | |
30 | + * @property Product $product | |
31 | + * @property Category[] $categories | |
32 | + * @property Category $category | |
33 | + * @property TaxOption[] $filters | |
34 | + * @property ProductStock[] $productStocks | |
35 | + * @property int $quantity | |
36 | + * @property ProductStock[] $variantStocks | |
37 | + * @property Stock[] $stocks | |
38 | + * @property TaxGroup[] $properties | |
39 | + * @property TaxGroup[] $taxGroupsByLevel | |
40 | + * * From language behavior * | |
41 | + * @property ProductVariantLang $lang | |
42 | + * @property ProductVariantLang[] $langs | |
43 | + * @property ProductVariantLang $objectLang | |
44 | + * @property string $ownerKey | |
45 | + * @property string $langKey | |
46 | + * @property ProductVariantLang[] $modelLangs | |
47 | + * @property bool $transactionStatus | |
48 | + * @method string getOwnerKey() | |
49 | + * @method void setOwnerKey( string $value ) | |
50 | + * @method string getLangKey() | |
51 | + * @method void setLangKey( string $value ) | |
52 | + * @method ActiveQuery getLangs() | |
53 | + * @method ActiveQuery getLang( integer $language_id ) | |
54 | + * @method ProductVariantLang[] generateLangs() | |
55 | + * @method void loadLangs( Request $request ) | |
56 | + * @method bool linkLangs() | |
57 | + * @method bool saveLangs() | |
58 | + * @method bool getTransactionStatus() | |
59 | + * * End language behavior * | |
60 | + * * From multipleImage behavior | |
61 | + * @property ProductImage $image | |
62 | + * @property ProductImage[] $images | |
63 | + * @property array $imagesConfig | |
64 | + * @method ActiveQuery getImage() | |
65 | + * @method ActiveQuery getImages() | |
66 | + * @method array getImagesConfig() | |
67 | + * @method array getImagesHTML( string $preset ) | |
68 | + * * End multipleImage behavior | |
69 | + */ | |
70 | + class ProductVariant extends ActiveRecord | |
71 | + { | |
72 | + /** | |
73 | + * @var int[] $options | |
74 | + */ | |
75 | + private $options; | |
76 | + | |
77 | + /** @var array $_images */ | |
78 | + public $imagesUpload = []; | |
79 | + | |
80 | + /** | |
81 | + * @var array $stocks | |
82 | + */ | |
83 | + protected $stocks = []; | |
84 | + | |
85 | + /** | |
86 | + * @inheritdoc | |
87 | + */ | |
88 | + public static function tableName() | |
89 | + { | |
90 | + return 'product_variant'; | |
91 | + } | |
92 | + | |
93 | + public function behaviors() | |
94 | + { | |
95 | + return [ | |
96 | + 'language' => [ | |
97 | + 'class' => LanguageBehavior::className(), | |
98 | + ], | |
99 | + 'images' => [ | |
100 | + 'class' => SaveMultipleFileBehavior::className(), | |
101 | + 'name' => 'imagesUpload', | |
102 | + 'directory' => 'products', | |
103 | + 'column' => 'image', | |
104 | + 'links' => [ | |
105 | + 'product_id' => 'product_id', | |
106 | + 'id' => 'product_variant_id', | |
107 | + ], | |
108 | + 'model' => ProductImage::className(), | |
109 | + ], | |
110 | + 'multipleImage' => [ | |
111 | + 'class' => MultipleImgBehavior::className(), | |
112 | + 'links' => [ | |
113 | + 'product_variant_id' => 'id', | |
114 | + ], | |
115 | + 'model' => ProductImage::className(), | |
116 | + 'config' => [ | |
117 | + 'caption' => 'image', | |
118 | + 'delete_action' => '/product/variant/delete-image', | |
119 | + 'id' => 'id', | |
120 | + ], | |
121 | + ], | |
122 | + ]; | |
123 | + } | |
124 | + | |
125 | + /** | |
126 | + * @inheritdoc | |
127 | + */ | |
128 | + public function rules() | |
129 | + { | |
130 | + return [ | |
131 | + [ | |
132 | + [ | |
133 | + 'product_id', | |
134 | + 'product_unit_id', | |
135 | + ], | |
136 | + 'required', | |
137 | + ], | |
138 | + [ | |
139 | + [ | |
140 | + 'product_id', | |
141 | + 'product_unit_id', | |
142 | + ], | |
143 | + 'integer', | |
144 | + ], | |
145 | + [ | |
146 | + [ | |
147 | + 'price', | |
148 | + 'price_old', | |
149 | + 'stock', | |
150 | + ], | |
151 | + 'number', | |
152 | + ], | |
153 | + [ | |
154 | + [ | |
155 | + 'sku', | |
156 | + ], | |
157 | + 'string', | |
158 | + 'max' => 255, | |
159 | + ], | |
160 | + [ | |
161 | + [ | |
162 | + 'options', | |
163 | + ], | |
164 | + 'safe', | |
165 | + ], | |
166 | + [ | |
167 | + [ 'product_unit_id' ], | |
168 | + 'exist', | |
169 | + 'skipOnError' => true, | |
170 | + 'targetClass' => ProductUnit::className(), | |
171 | + 'targetAttribute' => [ 'product_unit_id' => 'id' ], | |
172 | + ], | |
173 | + [ | |
174 | + [ 'product_id' ], | |
175 | + 'exist', | |
176 | + 'skipOnError' => true, | |
177 | + 'targetClass' => Product::className(), | |
178 | + 'targetAttribute' => [ 'product_id' => 'id' ], | |
179 | + ], | |
180 | + ]; | |
181 | + } | |
182 | + | |
183 | + /** | |
184 | + * @inheritdoc | |
185 | + */ | |
186 | + public function attributeLabels() | |
187 | + { | |
188 | + return [ | |
189 | + 'id' => Yii::t('product', 'Product Variant ID'), | |
190 | + 'product_id' => Yii::t('product', 'Product ID'), | |
191 | + 'sku' => Yii::t('product', 'Sku'), | |
192 | + 'price' => Yii::t('product', 'Price'), | |
193 | + 'price_old' => Yii::t('product', 'Price Old'), | |
194 | + 'stock' => Yii::t('product', 'Stock'), | |
195 | + 'product_unit_id' => Yii::t('product', 'Product Unit ID'), | |
196 | + 'stock_caption' => Yii::t('product', 'Stock'), | |
197 | + 'image' => Yii::t('product', 'Image'), | |
198 | + 'images' => Yii::t('product', 'Images'), | |
199 | + ]; | |
200 | + } | |
201 | + | |
202 | + /** | |
203 | + * @return \yii\db\ActiveQuery | |
204 | + */ | |
205 | + public function getProductUnit() | |
206 | + { | |
207 | + return $this->hasOne(ProductUnit::className(), [ 'id' => 'product_unit_id' ]); | |
208 | + } | |
209 | + | |
210 | + /** | |
211 | + * @return \yii\db\ActiveQuery | |
212 | + */ | |
213 | + public function getProduct() | |
214 | + { | |
215 | + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); | |
216 | + } | |
217 | + | |
218 | + /** | |
219 | + * @return \yii\db\ActiveQuery | |
220 | + */ | |
221 | + public function getProductStocks() | |
222 | + { | |
223 | + return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]); | |
224 | + } | |
225 | + | |
226 | + /** | |
227 | + * Get qunatity for current ProductVariant | |
228 | + * If $recalculate set to true will recalculate stock via product_stock table | |
229 | + * | |
230 | + * @param bool $recalculate | |
231 | + * | |
232 | + * @return int | |
233 | + */ | |
234 | + public function getQuantity(bool $recalculate = false): int | |
235 | + { | |
236 | + if (!$recalculate) { | |
237 | + return $this->stock; | |
238 | + } else { | |
239 | + $quantity = $this->getProductStocks() | |
240 | + ->sum('quantity'); | |
241 | + if (empty( $quantity )) { | |
242 | + $this->stock = 0; | |
243 | + } else { | |
244 | + $this->stock = (int) $quantity; | |
245 | + } | |
246 | + $this->save(false, [ 'stock' ]); | |
247 | + return $this->stock; | |
248 | + } | |
249 | + } | |
250 | + | |
251 | + /** | |
252 | + * Get ProductStocks query woth preloaded Stocks for current ProductVariant | |
253 | + * **Used in dynamic fields in product variant form** | |
254 | + * | |
255 | + * @return ActiveQuery | |
256 | + */ | |
257 | + public function getVariantStocks() | |
258 | + { | |
259 | + return $this->getProductStocks() | |
260 | + ->joinWith('stock'); | |
261 | + } | |
262 | + | |
263 | + /** | |
264 | + * @return ActiveQuery | |
265 | + */ | |
266 | + public function getStocks() | |
267 | + { | |
268 | + return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ]) | |
269 | + ->via('productStocks'); | |
270 | + } | |
271 | + | |
272 | + /** | |
273 | + * @return ActiveQuery | |
274 | + */ | |
275 | + public function getOptions() | |
276 | + { | |
277 | + return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) | |
278 | + ->viaTable('product_variant_option', [ 'product_variant_id' => 'id' ]); | |
279 | + } | |
280 | + | |
281 | + /** | |
282 | + * Get TaxOptions with preloaded TaxGroups for current ProductVariant | |
283 | + * | |
284 | + * @return ActiveQuery | |
285 | + */ | |
286 | + public function getFilters() | |
287 | + { | |
288 | + return $this->getOptions() | |
289 | + ->joinWith('taxGroup.lang') | |
290 | + ->joinWith('lang'); | |
291 | + } | |
292 | + | |
293 | + /** | |
294 | + * Get Product title concanated with current ProductVariant title | |
295 | + * | |
296 | + * @return string | |
297 | + */ | |
298 | + public function getFullname(): string | |
299 | + { | |
300 | + return $this->product->lang->title . ' ' . $this->lang->title; | |
301 | + } | |
302 | + | |
303 | + /** | |
304 | + * Set Options to override previous | |
305 | + * | |
306 | + * @param int[] $values | |
307 | + */ | |
308 | + public function setOptions($values) | |
309 | + { | |
310 | + $this->options = $values; | |
311 | + } | |
312 | + | |
313 | + /** | |
314 | + * Get all TaxGroups for current ProductVariant filled with $customOptions that satisfy current ProductVariant | |
315 | + * | |
316 | + * @return TaxGroup[] | |
317 | + */ | |
318 | + public function getProperties() | |
319 | + { | |
320 | + $groups = $options = []; | |
321 | + foreach ($this->getOptions() | |
322 | + ->with('lang') | |
323 | + ->all() as $option) { | |
324 | + /** | |
325 | + * @var TaxOption $option | |
326 | + */ | |
327 | + $options[ $option->tax_group_id ][] = $option; | |
328 | + } | |
329 | + foreach (TaxGroup::find() | |
330 | + ->where([ 'tax_group.id' => array_keys($options) ]) | |
331 | + ->orderBy([ 'sort' => SORT_ASC ]) | |
332 | + ->with('lang') | |
333 | + ->all() as $group) { | |
334 | + /** | |
335 | + * @var TaxGroup $group | |
336 | + */ | |
337 | + if (!empty( $options[ $group->id ] )) { | |
338 | + $group->customOptions = $options[ $group->id ]; | |
339 | + $groups[] = $group; | |
340 | + } | |
341 | + } | |
342 | + return $groups; | |
343 | + } | |
344 | + | |
345 | + /** | |
346 | + * Set stocks to override existing in product_stock table | |
347 | + * | |
348 | + * @param mixed $stocks | |
349 | + */ | |
350 | + public function setStocks($stocks) | |
351 | + { | |
352 | + $this->stocks = (array) $stocks; | |
353 | + } | |
354 | + | |
355 | + /** | |
356 | + * @return ActiveQuery | |
357 | + */ | |
358 | + public function getCategory() | |
359 | + { | |
360 | + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]) | |
361 | + ->viaTable('product_category', [ 'product_id' => 'product_id' ]); | |
362 | + } | |
363 | + | |
364 | + /** | |
365 | + * @return ActiveQuery | |
366 | + */ | |
367 | + public function getCategories() | |
368 | + { | |
369 | + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ]) | |
370 | + ->viaTable('product_category', [ 'product_id' => 'product_id' ]); | |
371 | + } | |
372 | + | |
373 | + /** | |
374 | + * Get TaxGroups query for current ProductVariant according to level | |
375 | + * * 0 - Product Tax Groups | |
376 | + * * 1 - ProductVariant Tax Groups | |
377 | + * | |
378 | + * @param int $level | |
379 | + * | |
380 | + * @return ActiveQuery | |
381 | + * @throws InvalidParamException | |
382 | + */ | |
383 | + public function getTaxGroupsByLevel(int $level = 0) | |
384 | + { | |
385 | + return $this->product->getTaxGroupsByLevel($level); | |
386 | + } | |
387 | + | |
388 | + public function afterSave($insert, $changedAttributes) | |
389 | + { | |
390 | + parent::afterSave($insert, $changedAttributes); | |
391 | + if (!empty( $this->options )) { | |
392 | + $options = TaxOption::findAll($this->options); | |
393 | + $this->unlinkAll('options', true); | |
394 | + foreach ($options as $option) { | |
395 | + $this->link('options', $option); | |
396 | + } | |
397 | + } | |
398 | + | |
399 | + if (!empty( $this->stocks )) { | |
400 | + ProductStock::deleteAll([ 'product_variant_id' => $this->id ]); | |
401 | + foreach ($this->stocks as $id => $quantity) { | |
402 | + /** | |
403 | + * @var ProductStock $productStock | |
404 | + */ | |
405 | + $productStock = ProductStock::find() | |
406 | + ->where( | |
407 | + [ | |
408 | + 'product_variant_id' => $this->id, | |
409 | + 'stock_id' => $id, | |
410 | + ] | |
411 | + ) | |
412 | + ->one(); | |
413 | + $productStock->quantity = $quantity; | |
414 | + $productStock->save(); | |
415 | + } | |
416 | + } | |
417 | + } | |
418 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductVariantLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "product_variant_lang". | |
11 | + * | |
12 | + * @property integer $product_variant_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $title | |
15 | + * @property Language $language | |
16 | + * @property ProductVariant $productVariant | |
17 | + */ | |
18 | + class ProductVariantLang extends ActiveRecord | |
19 | + { | |
20 | + | |
21 | + public static function primaryKey() | |
22 | + { | |
23 | + return [ | |
24 | + 'product_variant_id', | |
25 | + 'language_id', | |
26 | + ]; | |
27 | + } | |
28 | + | |
29 | + /** | |
30 | + * @inheritdoc | |
31 | + */ | |
32 | + public static function tableName() | |
33 | + { | |
34 | + return 'product_variant_lang'; | |
35 | + } | |
36 | + | |
37 | + /** | |
38 | + * @inheritdoc | |
39 | + */ | |
40 | + public function rules() | |
41 | + { | |
42 | + return [ | |
43 | + [ | |
44 | + [ 'title' ], | |
45 | + 'required', | |
46 | + ], | |
47 | + [ | |
48 | + [ 'title' ], | |
49 | + 'string', | |
50 | + 'max' => 255, | |
51 | + ], | |
52 | + [ | |
53 | + [ | |
54 | + 'product_variant_id', | |
55 | + 'language_id', | |
56 | + ], | |
57 | + 'unique', | |
58 | + 'targetAttribute' => [ | |
59 | + 'product_variant_id', | |
60 | + 'language_id', | |
61 | + ], | |
62 | + 'message' => 'The combination of Product Variant ID and Language ID has already been taken.', | |
63 | + ], | |
64 | + [ | |
65 | + [ 'language_id' ], | |
66 | + 'exist', | |
67 | + 'skipOnError' => true, | |
68 | + 'targetClass' => Language::className(), | |
69 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
70 | + ], | |
71 | + [ | |
72 | + [ 'product_variant_id' ], | |
73 | + 'exist', | |
74 | + 'skipOnError' => true, | |
75 | + 'targetClass' => ProductVariant::className(), | |
76 | + 'targetAttribute' => [ 'product_variant_id' => 'id' ], | |
77 | + ], | |
78 | + ]; | |
79 | + } | |
80 | + | |
81 | + /** | |
82 | + * @inheritdoc | |
83 | + */ | |
84 | + public function attributeLabels() | |
85 | + { | |
86 | + return [ | |
87 | + 'product_variant_id' => Yii::t('app', 'Product Variant ID'), | |
88 | + 'language_id' => Yii::t('app', 'Language ID'), | |
89 | + 'title' => Yii::t('app', 'Name'), | |
90 | + ]; | |
91 | + } | |
92 | + | |
93 | + /** | |
94 | + * @return \yii\db\ActiveQuery | |
95 | + */ | |
96 | + public function getLanguage() | |
97 | + { | |
98 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
99 | + } | |
100 | + | |
101 | + /** | |
102 | + * @return \yii\db\ActiveQuery | |
103 | + */ | |
104 | + public function getProductVariant() | |
105 | + { | |
106 | + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]); | |
107 | + } | |
108 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductVariantOption.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\TaxOption; | |
6 | + use yii\db\ActiveRecord; | |
7 | + | |
8 | + /** | |
9 | + * This is the model class for table "product_variant_option". | |
10 | + * | |
11 | + * @property integer $product_variant_id | |
12 | + * @property integer $option_id | |
13 | + * @property ProductVariant $productVariant | |
14 | + * @property TaxOption $option | |
15 | + */ | |
16 | + class ProductVariantOption extends ActiveRecord | |
17 | + { | |
18 | + | |
19 | + /** | |
20 | + * @inheritdoc | |
21 | + */ | |
22 | + public static function tableName() | |
23 | + { | |
24 | + return 'product_variant_option'; | |
25 | + } | |
26 | + | |
27 | + /** | |
28 | + * @inheritdoc | |
29 | + */ | |
30 | + public function rules() | |
31 | + { | |
32 | + return [ | |
33 | + [ | |
34 | + [ | |
35 | + 'product_variant_id', | |
36 | + 'option_id', | |
37 | + ], | |
38 | + 'required', | |
39 | + ], | |
40 | + [ | |
41 | + [ | |
42 | + 'product_variant_id', | |
43 | + 'option_id', | |
44 | + ], | |
45 | + 'integer', | |
46 | + ], | |
47 | + [ | |
48 | + [ 'product_variant_id' ], | |
49 | + 'exist', | |
50 | + 'skipOnError' => true, | |
51 | + 'targetClass' => ProductVariant::className(), | |
52 | + 'targetAttribute' => [ 'product_variant_id' => 'id' ], | |
53 | + ], | |
54 | + [ | |
55 | + [ 'option_id' ], | |
56 | + 'exist', | |
57 | + 'skipOnError' => true, | |
58 | + 'targetClass' => TaxOption::className(), | |
59 | + 'targetAttribute' => [ 'option_id' => 'id' ], | |
60 | + ], | |
61 | + ]; | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * @inheritdoc | |
66 | + */ | |
67 | + public function attributeLabels() | |
68 | + { | |
69 | + return [ | |
70 | + 'product_variant_id' => 'Product Variant ID', | |
71 | + 'option_id' => 'Option ID', | |
72 | + ]; | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * @return \yii\db\ActiveQuery | |
77 | + */ | |
78 | + public function getProductVariant() | |
79 | + { | |
80 | + return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]); | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @return \yii\db\ActiveQuery | |
85 | + */ | |
86 | + public function getOption() | |
87 | + { | |
88 | + return $this->hasOne(TaxOption::className(), [ 'id' => 'option_id' ]); | |
89 | + } | |
90 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/ProductVariantSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * ProductVariantSearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\ProductVariant`. | |
11 | + */ | |
12 | + class ProductVariantSearch extends ProductVariant | |
13 | + { | |
14 | + | |
15 | + public $variantName; | |
16 | + | |
17 | + public function behaviors() | |
18 | + { | |
19 | + return []; | |
20 | + } | |
21 | + | |
22 | + /** | |
23 | + * @inheritdoc | |
24 | + */ | |
25 | + public function rules() | |
26 | + { | |
27 | + return [ | |
28 | + [ | |
29 | + [ | |
30 | + 'variantName', | |
31 | + 'sku', | |
32 | + ], | |
33 | + 'safe', | |
34 | + ], | |
35 | + [ | |
36 | + [ | |
37 | + 'id', | |
38 | + 'stock', | |
39 | + ], | |
40 | + 'integer', | |
41 | + ], | |
42 | + [ | |
43 | + [ | |
44 | + 'price', | |
45 | + 'price_old', | |
46 | + ], | |
47 | + 'number', | |
48 | + ], | |
49 | + ]; | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * @inheritdoc | |
54 | + */ | |
55 | + public function scenarios() | |
56 | + { | |
57 | + // bypass scenarios() implementation in the parent class | |
58 | + return Model::scenarios(); | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * Creates data provider instance with search query applied | |
63 | + * | |
64 | + * @param array $params | |
65 | + * | |
66 | + * @return ActiveDataProvider | |
67 | + */ | |
68 | + public function search($params) | |
69 | + { | |
70 | + $query = ProductVariant::find() | |
71 | + ->joinWith('lang'); | |
72 | + | |
73 | + // add conditions that should always apply here | |
74 | + | |
75 | + $dataProvider = new ActiveDataProvider( | |
76 | + [ | |
77 | + 'query' => $query, | |
78 | + ] | |
79 | + ); | |
80 | + | |
81 | + $this->load($params); | |
82 | + | |
83 | + if (!$this->validate()) { | |
84 | + // uncomment the following line if you do not want to return any records when validation fails | |
85 | + // $query->where('0=1'); | |
86 | + return $dataProvider; | |
87 | + } | |
88 | + | |
89 | + $dataProvider->setSort( | |
90 | + [ | |
91 | + 'attributes' => [ | |
92 | + 'id', | |
93 | + 'sku', | |
94 | + 'variantName' => [ | |
95 | + 'asc' => [ 'product_variant_lang.title' => SORT_ASC ], | |
96 | + 'desc' => [ 'product_variant_lang.title' => SORT_DESC ], | |
97 | + ], | |
98 | + 'price', | |
99 | + 'price_old', | |
100 | + 'stock', | |
101 | + ], | |
102 | + ] | |
103 | + ); | |
104 | + | |
105 | + $query->andFilterWhere( | |
106 | + [ | |
107 | + 'price' => $this->price, | |
108 | + 'price_old' => $this->price_old, | |
109 | + 'stock' => $this->stock, | |
110 | + ] | |
111 | + ); | |
112 | + | |
113 | + $query->andFilterWhere( | |
114 | + [ | |
115 | + 'ilike', | |
116 | + 'product_variant_lang.title', | |
117 | + $this->variantName, | |
118 | + ] | |
119 | + ) | |
120 | + ->andFilterWhere( | |
121 | + [ | |
122 | + 'ilike', | |
123 | + 'sku', | |
124 | + $this->sku, | |
125 | + ] | |
126 | + ); | |
127 | + | |
128 | + $query->groupBy( | |
129 | + [ | |
130 | + 'product_variant.id', | |
131 | + 'product_variant_lang.title', | |
132 | + ] | |
133 | + ); | |
134 | + | |
135 | + return $dataProvider; | |
136 | + } | |
137 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/Stock.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\behaviors\LanguageBehavior; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveQuery; | |
8 | + use yii\db\ActiveRecord; | |
9 | + use yii\web\Request; | |
10 | + | |
11 | + /** | |
12 | + * This is the model class for table "stock". | |
13 | + * | |
14 | + * @property integer $id | |
15 | + * @property ProductStock[] $productStocks | |
16 | + * @property ProductVariant[] $productVariants | |
17 | + * @property Product[] $products | |
18 | + * * From language behavior * | |
19 | + * @property StockLang $lang | |
20 | + * @property StockLang[] $langs | |
21 | + * @property StockLang $objectLang | |
22 | + * @property string $ownerKey | |
23 | + * @property string $langKey | |
24 | + * @property StockLang[] $modelLangs | |
25 | + * @property bool $transactionStatus | |
26 | + * @method string getOwnerKey() | |
27 | + * @method void setOwnerKey( string $value ) | |
28 | + * @method string getLangKey() | |
29 | + * @method void setLangKey( string $value ) | |
30 | + * @method ActiveQuery getLangs() | |
31 | + * @method ActiveQuery getLang( integer $language_id ) | |
32 | + * @method StockLang[] generateLangs() | |
33 | + * @method void loadLangs( Request $request ) | |
34 | + * @method bool linkLangs() | |
35 | + * @method bool saveLangs() | |
36 | + * @method bool getTransactionStatus() | |
37 | + * * End language behavior * | |
38 | + */ | |
39 | + class Stock extends ActiveRecord | |
40 | + { | |
41 | + /** | |
42 | + * @inheritdoc | |
43 | + */ | |
44 | + public static function tableName() | |
45 | + { | |
46 | + return 'stock'; | |
47 | + } | |
48 | + | |
49 | + public function behaviors() | |
50 | + { | |
51 | + return [ | |
52 | + 'language' => [ | |
53 | + 'class' => LanguageBehavior::className(), | |
54 | + ], | |
55 | + ]; | |
56 | + } | |
57 | + | |
58 | + /** | |
59 | + * @inheritdoc | |
60 | + */ | |
61 | + public function attributeLabels() | |
62 | + { | |
63 | + return [ | |
64 | + 'id' => Yii::t('product', 'Stock ID'), | |
65 | + ]; | |
66 | + } | |
67 | + | |
68 | + /** | |
69 | + * @return \yii\db\ActiveQuery | |
70 | + */ | |
71 | + public function getProductStocks() | |
72 | + { | |
73 | + return $this->hasMany(ProductStock::className(), [ 'stock_id' => 'id' ]); | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * @return ActiveQuery | |
78 | + */ | |
79 | + public function getProductVariants() | |
80 | + { | |
81 | + return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ]) | |
82 | + ->via('productStocks'); | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * @return ActiveQuery | |
87 | + */ | |
88 | + public function getProducts() | |
89 | + { | |
90 | + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ]) | |
91 | + ->via('productVariants'); | |
92 | + } | |
93 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/StockLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "brand_lang". | |
11 | + * | |
12 | + * @property integer $stock_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $title | |
15 | + * @property Stock $stock | |
16 | + * @property Language $language | |
17 | + */ | |
18 | + class StockLang extends ActiveRecord | |
19 | + { | |
20 | + | |
21 | + public static function primaryKey() | |
22 | + { | |
23 | + return [ | |
24 | + 'stock_id', | |
25 | + 'language_id', | |
26 | + ]; | |
27 | + } | |
28 | + | |
29 | + /** | |
30 | + * @inheritdoc | |
31 | + */ | |
32 | + public static function tableName() | |
33 | + { | |
34 | + return 'stock_lang'; | |
35 | + } | |
36 | + | |
37 | + /** | |
38 | + * @inheritdoc | |
39 | + */ | |
40 | + public function rules() | |
41 | + { | |
42 | + return [ | |
43 | + [ | |
44 | + [ 'title' ], | |
45 | + 'required', | |
46 | + ], | |
47 | + [ | |
48 | + [ | |
49 | + 'title', | |
50 | + ], | |
51 | + 'string', | |
52 | + 'max' => 255, | |
53 | + ], | |
54 | + [ | |
55 | + [ | |
56 | + 'stock_id', | |
57 | + 'language_id', | |
58 | + ], | |
59 | + 'unique', | |
60 | + 'targetAttribute' => [ | |
61 | + 'stock_id', | |
62 | + 'language_id', | |
63 | + ], | |
64 | + 'message' => 'The combination of Stock ID and Language ID has already been taken.', | |
65 | + ], | |
66 | + [ | |
67 | + [ 'stock_id' ], | |
68 | + 'exist', | |
69 | + 'skipOnError' => true, | |
70 | + 'targetClass' => Stock::className(), | |
71 | + 'targetAttribute' => [ 'stock_id' => 'id' ], | |
72 | + ], | |
73 | + [ | |
74 | + [ 'language_id' ], | |
75 | + 'exist', | |
76 | + 'skipOnError' => true, | |
77 | + 'targetClass' => Language::className(), | |
78 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
79 | + ], | |
80 | + ]; | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @inheritdoc | |
85 | + */ | |
86 | + public function attributeLabels() | |
87 | + { | |
88 | + return [ | |
89 | + 'stock_id' => Yii::t('app', 'Stock ID'), | |
90 | + 'language_id' => Yii::t('app', 'Language ID'), | |
91 | + 'title' => Yii::t('app', 'Name'), | |
92 | + ]; | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * @return \yii\db\ActiveQuery | |
97 | + */ | |
98 | + public function getStock() | |
99 | + { | |
100 | + return $this->hasOne(Stock::className(), [ 'id' => 'stock_id' ]); | |
101 | + } | |
102 | + | |
103 | + /** | |
104 | + * @return \yii\db\ActiveQuery | |
105 | + */ | |
106 | + public function getLanguage() | |
107 | + { | |
108 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
109 | + } | |
110 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxGroup.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\behaviors\LanguageBehavior; | |
6 | + use common\modules\language\models\Language; | |
7 | + use artweb\artbox\ecommerce\models\Category; | |
8 | + use yii\base\InvalidValueException; | |
9 | + use yii\db\ActiveQuery; | |
10 | + use yii\db\ActiveRecord; | |
11 | + use yii\web\Request; | |
12 | + | |
13 | + /** | |
14 | + * This is the model class for table "{{%tax_group}}". | |
15 | + * | |
16 | + * @property integer $id | |
17 | + * @property boolean $is_filter | |
18 | + * @property integer $level | |
19 | + * @property integer $sort | |
20 | + * @property boolean $display | |
21 | + * @property boolean $is_menu | |
22 | + * @property string $remote_id | |
23 | + * @property TaxOption[] $taxOptions | |
24 | + * @property Category[] $categories | |
25 | + * @property TaxOption[] $options | |
26 | + * @property TaxOption[] $customOptions | |
27 | + * @property string $alias | |
28 | + * * From language behavior * | |
29 | + * @property TaxGroupLang $lang | |
30 | + * @property TaxGroupLang[] $langs | |
31 | + * @property TaxGroupLang $objectLang | |
32 | + * @property string $ownerKey | |
33 | + * @property string $langKey | |
34 | + * @property TaxGroupLang[] $modelLangs | |
35 | + * @property bool $transactionStatus | |
36 | + * @method string getOwnerKey() | |
37 | + * @method void setOwnerKey( string $value ) | |
38 | + * @method string getLangKey() | |
39 | + * @method void setLangKey( string $value ) | |
40 | + * @method ActiveQuery getLangs() | |
41 | + * @method ActiveQuery getLang( integer $language_id ) | |
42 | + * @method TaxGroupLang[] generateLangs() | |
43 | + * @method void loadLangs( Request $request ) | |
44 | + * @method bool linkLangs() | |
45 | + * @method bool saveLangs() | |
46 | + * @method bool getTransactionStatus() | |
47 | + * * End language behavior * | |
48 | + */ | |
49 | + class TaxGroup extends ActiveRecord | |
50 | + { | |
51 | + | |
52 | + const GROUP_PRODUCT = 0; | |
53 | + const GROUP_VARIANT = 1; | |
54 | + | |
55 | + /** | |
56 | + * @var TaxOption[] $options | |
57 | + */ | |
58 | + protected $customOptions = []; | |
59 | + | |
60 | + /** | |
61 | + * @inheritdoc | |
62 | + */ | |
63 | + public function behaviors() | |
64 | + { | |
65 | + return [ | |
66 | + 'language' => [ | |
67 | + 'class' => LanguageBehavior::className(), | |
68 | + ], | |
69 | + ]; | |
70 | + } | |
71 | + | |
72 | + /** | |
73 | + * @inheritdoc | |
74 | + */ | |
75 | + public static function tableName() | |
76 | + { | |
77 | + return 'tax_group'; | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * @inheritdoc | |
82 | + */ | |
83 | + public function rules() | |
84 | + { | |
85 | + return [ | |
86 | + [ | |
87 | + [ | |
88 | + 'is_filter', | |
89 | + 'display', | |
90 | + 'is_menu', | |
91 | + ], | |
92 | + 'boolean', | |
93 | + ], | |
94 | + [ | |
95 | + [ | |
96 | + 'level', | |
97 | + 'sort', | |
98 | + ], | |
99 | + 'integer', | |
100 | + ], | |
101 | + [ | |
102 | + [ 'categories' ], | |
103 | + 'safe', | |
104 | + ], | |
105 | + ]; | |
106 | + } | |
107 | + | |
108 | + /** | |
109 | + * @inheritdoc | |
110 | + */ | |
111 | + public function attributeLabels() | |
112 | + { | |
113 | + return [ | |
114 | + 'id' => 'Tax Group ID', | |
115 | + 'is_filter' => 'Use in filter', | |
116 | + 'sort' => 'Sort', | |
117 | + 'display' => 'Display', | |
118 | + 'is_menu' => 'Отображать в меню', | |
119 | + ]; | |
120 | + } | |
121 | + | |
122 | + /** | |
123 | + * @return ActiveQuery | |
124 | + */ | |
125 | + public function getCategories() | |
126 | + { | |
127 | + return $this->hasMany(Category::className(), [ 'id' => 'category_id' ]) | |
128 | + ->viaTable('tax_group_to_category', [ 'tax_group_id' => 'id' ]); | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * Set categories to override tax_group_to_category table data | |
133 | + * | |
134 | + * @param int[] $values | |
135 | + */ | |
136 | + public function setCategories(array $values) | |
137 | + { | |
138 | + $this->categories = $values; | |
139 | + } | |
140 | + | |
141 | + /** | |
142 | + * @inheritdoc | |
143 | + */ | |
144 | + public function afterSave($insert, $changedAttributes) | |
145 | + { | |
146 | + parent::afterSave($insert, $changedAttributes); | |
147 | + $this->unlinkAll('categories', true); | |
148 | + $categories = []; | |
149 | + if (!empty( $this->categories )) { | |
150 | + $categories = Category::findAll($this->categories); | |
151 | + } | |
152 | + foreach ($categories as $category) { | |
153 | + $this->link('categories', $category); | |
154 | + } | |
155 | + } | |
156 | + | |
157 | + /** | |
158 | + * @return ActiveQuery | |
159 | + */ | |
160 | + public function getTaxOptions() | |
161 | + { | |
162 | + return $this->hasMany(TaxOption::className(), [ 'tax_group_id' => 'id' ]) | |
163 | + ->inverseOf('taxGroup'); | |
164 | + } | |
165 | + | |
166 | + /** | |
167 | + * Synonim for getTaxOptions() | |
168 | + * | |
169 | + * @see TaxGroup::getTaxOptions() | |
170 | + * @return \yii\db\ActiveQuery | |
171 | + */ | |
172 | + public function getOptions() | |
173 | + { | |
174 | + return $this->getTaxOptions(); | |
175 | + } | |
176 | + | |
177 | + /** | |
178 | + * Get customOptins that were filled dynamically. | |
179 | + * If $fillDefault is true then fill $customOptions with TaxOptions for current TaxGroup | |
180 | + * | |
181 | + * @param bool $fillDefault | |
182 | + * | |
183 | + * @return TaxOption[] | |
184 | + */ | |
185 | + public function getCustomOptions(bool $fillDefault = false): array | |
186 | + { | |
187 | + if ($fillDefault && empty( $this->custom_options )) { | |
188 | + $this->customOptions = $this->getTaxOptions() | |
189 | + ->with('lang') | |
190 | + ->all(); | |
191 | + } | |
192 | + return $this->customOptions; | |
193 | + } | |
194 | + | |
195 | + /** | |
196 | + * Set customOptions | |
197 | + * | |
198 | + * @param TaxOption[] $value | |
199 | + */ | |
200 | + public function setCustomOptions(array $value) | |
201 | + { | |
202 | + foreach ($value as $item) { | |
203 | + if (!( $item instanceof TaxOption )) { | |
204 | + throw new InvalidValueException('All elements must be instances of ' . TaxOption::className()); | |
205 | + } | |
206 | + } | |
207 | + $this->customOptions = $value; | |
208 | + } | |
209 | + | |
210 | + /** | |
211 | + * Get default lang alias | |
212 | + * | |
213 | + * @return string | |
214 | + */ | |
215 | + public function getAlias() | |
216 | + { | |
217 | + $default_lang = Language::getDefaultLanguage(); | |
218 | + /** | |
219 | + * @var TaxGroupLang $lang | |
220 | + */ | |
221 | + $lang = $this->getLang($default_lang->id) | |
222 | + ->one(); | |
223 | + return $lang->alias; | |
224 | + } | |
225 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxGroupLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "tax_group_lang". | |
11 | + * | |
12 | + * @property integer $tax_group_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $title | |
15 | + * @property string $alias | |
16 | + * @property string $description | |
17 | + * @property Language $language | |
18 | + * @property TaxGroup $taxGroup | |
19 | + */ | |
20 | + class TaxGroupLang extends ActiveRecord | |
21 | + { | |
22 | + | |
23 | + public static function primaryKey() | |
24 | + { | |
25 | + return [ | |
26 | + 'tax_group_id', | |
27 | + 'language_id', | |
28 | + ]; | |
29 | + } | |
30 | + | |
31 | + /** | |
32 | + * @inheritdoc | |
33 | + */ | |
34 | + public static function tableName() | |
35 | + { | |
36 | + return 'tax_group_lang'; | |
37 | + } | |
38 | + | |
39 | + public function behaviors() | |
40 | + { | |
41 | + return [ | |
42 | + 'slug' => [ | |
43 | + 'class' => 'common\behaviors\Slug', | |
44 | + ], | |
45 | + ]; | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * @inheritdoc | |
50 | + */ | |
51 | + public function rules() | |
52 | + { | |
53 | + return [ | |
54 | + [ | |
55 | + [ 'title' ], | |
56 | + 'required', | |
57 | + ], | |
58 | + [ | |
59 | + [ 'description' ], | |
60 | + 'string', | |
61 | + ], | |
62 | + [ | |
63 | + [ | |
64 | + 'title', | |
65 | + 'alias', | |
66 | + ], | |
67 | + 'string', | |
68 | + 'max' => 255, | |
69 | + ], | |
70 | + [ | |
71 | + [ | |
72 | + 'tax_group_id', | |
73 | + 'language_id', | |
74 | + ], | |
75 | + 'unique', | |
76 | + 'targetAttribute' => [ | |
77 | + 'tax_group_id', | |
78 | + 'language_id', | |
79 | + ], | |
80 | + 'message' => 'The combination of Tax Group ID and Language ID has already been taken.', | |
81 | + ], | |
82 | + [ | |
83 | + [ 'language_id' ], | |
84 | + 'exist', | |
85 | + 'skipOnError' => true, | |
86 | + 'targetClass' => Language::className(), | |
87 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
88 | + ], | |
89 | + [ | |
90 | + [ 'tax_group_id' ], | |
91 | + 'exist', | |
92 | + 'skipOnError' => true, | |
93 | + 'targetClass' => TaxGroup::className(), | |
94 | + 'targetAttribute' => [ 'tax_group_id' => 'id' ], | |
95 | + ], | |
96 | + ]; | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * @inheritdoc | |
101 | + */ | |
102 | + public function attributeLabels() | |
103 | + { | |
104 | + return [ | |
105 | + 'tax_group_id' => Yii::t('app', 'Tax Group ID'), | |
106 | + 'language_id' => Yii::t('app', 'Language ID'), | |
107 | + 'title' => Yii::t('app', 'Name'), | |
108 | + 'description' => Yii::t('app', 'Description'), | |
109 | + 'alias' => Yii::t('app', 'Alias'), | |
110 | + ]; | |
111 | + } | |
112 | + | |
113 | + /** | |
114 | + * @return \yii\db\ActiveQuery | |
115 | + */ | |
116 | + public function getLanguage() | |
117 | + { | |
118 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
119 | + } | |
120 | + | |
121 | + /** | |
122 | + * @return \yii\db\ActiveQuery | |
123 | + */ | |
124 | + public function getTaxGroup() | |
125 | + { | |
126 | + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]); | |
127 | + } | |
128 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxGroupSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * TaxGroupSearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\TaxGroup`. | |
11 | + */ | |
12 | + class TaxGroupSearch extends TaxGroup | |
13 | + { | |
14 | + | |
15 | + public $groupName; | |
16 | + | |
17 | + public function behaviors() | |
18 | + { | |
19 | + $behaviors = parent::behaviors(); | |
20 | + if (isset( $behaviors[ 'language' ] )) { | |
21 | + unset( $behaviors[ 'language' ] ); | |
22 | + } | |
23 | + return $behaviors; | |
24 | + } | |
25 | + | |
26 | + /** | |
27 | + * @inheritdoc | |
28 | + */ | |
29 | + public function rules() | |
30 | + { | |
31 | + return [ | |
32 | + [ | |
33 | + [ | |
34 | + 'id', | |
35 | + 'level', | |
36 | + ], | |
37 | + 'integer', | |
38 | + ], | |
39 | + [ | |
40 | + [ | |
41 | + 'is_filter', | |
42 | + ], | |
43 | + 'boolean', | |
44 | + ], | |
45 | + [ | |
46 | + [ | |
47 | + 'groupName', | |
48 | + ], | |
49 | + 'safe', | |
50 | + ], | |
51 | + ]; | |
52 | + } | |
53 | + | |
54 | + /** | |
55 | + * @inheritdoc | |
56 | + */ | |
57 | + public function scenarios() | |
58 | + { | |
59 | + // bypass scenarios() implementation in the parent class | |
60 | + return Model::scenarios(); | |
61 | + } | |
62 | + | |
63 | + /** | |
64 | + * Creates data provider instance with search query applied | |
65 | + * | |
66 | + * @param array $params | |
67 | + * | |
68 | + * @return ActiveDataProvider | |
69 | + */ | |
70 | + public function search($params, int $level = null) | |
71 | + { | |
72 | + $query = TaxGroup::find() | |
73 | + ->joinWith('lang'); | |
74 | + | |
75 | + $dataProvider = new ActiveDataProvider( | |
76 | + [ | |
77 | + 'query' => $query, | |
78 | + 'sort' => [ | |
79 | + 'attributes' => [ | |
80 | + 'id', | |
81 | + 'is_filter', | |
82 | + 'groupName' => [ | |
83 | + 'asc' => [ 'tax_group_lang.title' => SORT_ASC ], | |
84 | + 'desc' => [ 'tax_group_lang.title' => SORT_DESC ], | |
85 | + ], | |
86 | + ], | |
87 | + ], | |
88 | + ] | |
89 | + ); | |
90 | + | |
91 | + $this->load($params); | |
92 | + | |
93 | + if (!is_null($level)) { | |
94 | + $this->level = $level; | |
95 | + } | |
96 | + | |
97 | + if (!$this->validate()) { | |
98 | + // uncomment the following line if you do not want to return any records when validation fails | |
99 | + // $query->where('0=1'); | |
100 | + return $dataProvider; | |
101 | + } | |
102 | + | |
103 | + $query->andFilterWhere( | |
104 | + [ | |
105 | + 'id' => $this->id, | |
106 | + 'is_filter' => $this->is_filter, | |
107 | + 'level' => $this->level, | |
108 | + ] | |
109 | + ) | |
110 | + ->andFilterWhere( | |
111 | + [ | |
112 | + 'ilike', | |
113 | + 'tax_group_lang.title', | |
114 | + $this->groupName, | |
115 | + ] | |
116 | + ); | |
117 | + | |
118 | + return $dataProvider; | |
119 | + } | |
120 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxGroupToCategory.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\Category; | |
6 | + use yii\db\ActiveRecord; | |
7 | + | |
8 | + /** | |
9 | + * This is the model class for table "tax_group_to_category". | |
10 | + * | |
11 | + * @property integer $tax_group_to_category_id | |
12 | + * @property integer $tax_group_id | |
13 | + * @property integer $category_id | |
14 | + * @property Category $category | |
15 | + * @property TaxGroup $taxGroup | |
16 | + */ | |
17 | + class TaxGroupToCategory extends ActiveRecord | |
18 | + { | |
19 | + | |
20 | + /** | |
21 | + * @inheritdoc | |
22 | + */ | |
23 | + public static function tableName() | |
24 | + { | |
25 | + return 'tax_group_to_category'; | |
26 | + } | |
27 | + | |
28 | + /** | |
29 | + * @inheritdoc | |
30 | + */ | |
31 | + public function rules() | |
32 | + { | |
33 | + return [ | |
34 | + [ | |
35 | + [ | |
36 | + 'tax_group_id', | |
37 | + 'category_id', | |
38 | + ], | |
39 | + 'required', | |
40 | + ], | |
41 | + [ | |
42 | + [ | |
43 | + 'tax_group_id', | |
44 | + 'category_id', | |
45 | + ], | |
46 | + 'integer', | |
47 | + ], | |
48 | + [ | |
49 | + [ 'category_id' ], | |
50 | + 'exist', | |
51 | + 'skipOnError' => true, | |
52 | + 'targetClass' => Category::className(), | |
53 | + 'targetAttribute' => [ 'category_id' => 'id' ], | |
54 | + ], | |
55 | + [ | |
56 | + [ 'tax_group_id' ], | |
57 | + 'exist', | |
58 | + 'skipOnError' => true, | |
59 | + 'targetClass' => TaxGroup::className(), | |
60 | + 'targetAttribute' => [ 'tax_group_id' => 'id' ], | |
61 | + ], | |
62 | + ]; | |
63 | + } | |
64 | + | |
65 | + /** | |
66 | + * @inheritdoc | |
67 | + */ | |
68 | + public function attributeLabels() | |
69 | + { | |
70 | + return [ | |
71 | + 'tax_group_to_category_id' => 'Tax Group To Category ID', | |
72 | + 'tax_group_id' => 'Tax Group ID', | |
73 | + 'category_id' => 'Category ID', | |
74 | + ]; | |
75 | + } | |
76 | + | |
77 | + /** | |
78 | + * @return \yii\db\ActiveQuery | |
79 | + */ | |
80 | + public function getCategory() | |
81 | + { | |
82 | + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]); | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * @return \yii\db\ActiveQuery | |
87 | + */ | |
88 | + public function getTaxGroup() | |
89 | + { | |
90 | + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]); | |
91 | + } | |
92 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxOption.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\behaviors\SaveImgBehavior; | |
6 | + use common\modules\language\behaviors\LanguageBehavior; | |
7 | + use artweb\artbox\ecommerce\models\Product; | |
8 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
9 | + use Yii; | |
10 | + use yii\db\ActiveQuery; | |
11 | + use yii\db\ActiveRecord; | |
12 | + use yii\web\Request; | |
13 | + | |
14 | + /** | |
15 | + * This is the model class for table "{{%tax_option}}". | |
16 | + * | |
17 | + * @property string $id | |
18 | + * @property integer $tax_group_id | |
19 | + * @property integer $tree | |
20 | + * @property integer $sort | |
21 | + * @property string $image | |
22 | + * @property TaxGroup $taxGroup | |
23 | + * @property TaxGroup $group | |
24 | + * @property Product[] $products | |
25 | + * @property ProductVariant[] $productVariants | |
26 | + * * From language behavior * | |
27 | + * @property TaxOptionLang $lang | |
28 | + * @property TaxOptionLang[] $langs | |
29 | + * @property TaxOptionLang $objectLang | |
30 | + * @property string $ownerKey | |
31 | + * @property string $langKey | |
32 | + * @property TaxOptionLang[] $modelLangs | |
33 | + * @property bool $transactionStatus | |
34 | + * @method string getOwnerKey() | |
35 | + * @method void setOwnerKey( string $value ) | |
36 | + * @method string getLangKey() | |
37 | + * @method void setLangKey( string $value ) | |
38 | + * @method ActiveQuery getLangs() | |
39 | + * @method ActiveQuery getLang( integer $language_id ) | |
40 | + * @method TaxOptionLang[] generateLangs() | |
41 | + * @method void loadLangs( Request $request ) | |
42 | + * @method bool linkLangs() | |
43 | + * @method bool saveLangs() | |
44 | + * @method bool getTransactionStatus() | |
45 | + * * End language behavior * | |
46 | + * * From SaveImgBehavior | |
47 | + * @property string|null $imageFile | |
48 | + * @property string|null $imageUrl | |
49 | + * @method string|null getImageFile( int $field ) | |
50 | + * @method string|null getImageUrl( int $field ) | |
51 | + * * End SaveImgBehavior | |
52 | + */ | |
53 | + class TaxOption extends ActiveRecord | |
54 | + { | |
55 | + | |
56 | + /** | |
57 | + * @inheritdoc | |
58 | + */ | |
59 | + public function behaviors() | |
60 | + { | |
61 | + return [ | |
62 | + [ | |
63 | + 'class' => SaveImgBehavior::className(), | |
64 | + 'fields' => [ | |
65 | + [ | |
66 | + 'name' => 'image', | |
67 | + 'directory' => 'tax_option', | |
68 | + ], | |
69 | + ], | |
70 | + ], | |
71 | + 'language' => [ | |
72 | + 'class' => LanguageBehavior::className(), | |
73 | + ], | |
74 | + ]; | |
75 | + } | |
76 | + | |
77 | + /** | |
78 | + * @inheritdoc | |
79 | + */ | |
80 | + public static function tableName() | |
81 | + { | |
82 | + return '{{%tax_option}}'; | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * @inheritdoc | |
87 | + */ | |
88 | + public function rules() | |
89 | + { | |
90 | + return [ | |
91 | + [ | |
92 | + [ | |
93 | + 'tax_group_id', | |
94 | + 'sort', | |
95 | + ], | |
96 | + 'integer', | |
97 | + ], | |
98 | + [ | |
99 | + [ 'tax_group_id' ], | |
100 | + 'exist', | |
101 | + 'skipOnError' => true, | |
102 | + 'targetClass' => TaxGroup::className(), | |
103 | + 'targetAttribute' => [ 'tax_group_id' => 'id' ], | |
104 | + ], | |
105 | + ]; | |
106 | + } | |
107 | + | |
108 | + /** | |
109 | + * @inheritdoc | |
110 | + */ | |
111 | + public function attributeLabels() | |
112 | + { | |
113 | + return [ | |
114 | + 'id' => Yii::t('app', 'Tax Option ID'), | |
115 | + 'tax_group_id' => Yii::t('app', 'Tax Group ID'), | |
116 | + 'sort' => Yii::t('app', 'Sort'), | |
117 | + 'image' => Yii::t('product', 'Image'), | |
118 | + ]; | |
119 | + } | |
120 | + | |
121 | + /** | |
122 | + * @return \yii\db\ActiveQuery | |
123 | + */ | |
124 | + public function getTaxGroup() | |
125 | + { | |
126 | + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) | |
127 | + ->inverseOf('taxOptions'); | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * Synonim for TaxOption::getTaxGroup() | |
132 | + * | |
133 | + * @see TaxOption::getTaxGroup() | |
134 | + * @return \yii\db\ActiveQuery | |
135 | + */ | |
136 | + public function getGroup() | |
137 | + { | |
138 | + return $this->getTaxGroup(); | |
139 | + } | |
140 | + | |
141 | + /** | |
142 | + * @return ActiveQuery | |
143 | + */ | |
144 | + public function getProducts() | |
145 | + { | |
146 | + return $this->hasMany(Product::className(), [ 'id' => 'product_id' ]) | |
147 | + ->viaTable('product_option', [ 'option_id' => 'id' ]); | |
148 | + } | |
149 | + | |
150 | + /** | |
151 | + * @return ActiveQuery | |
152 | + */ | |
153 | + public function getProductVariants() | |
154 | + { | |
155 | + return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ]) | |
156 | + ->viaTable('product_variant_option', [ 'option_id' => 'id' ]); | |
157 | + } | |
158 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxOptionLang.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use common\modules\language\models\Language; | |
6 | + use Yii; | |
7 | + use yii\db\ActiveRecord; | |
8 | + | |
9 | + /** | |
10 | + * This is the model class for table "tax_option_lang". | |
11 | + * | |
12 | + * @property integer $tax_option_id | |
13 | + * @property integer $language_id | |
14 | + * @property string $value | |
15 | + * @property string $alias | |
16 | + * @property Language $language | |
17 | + * @property TaxOption $taxOption | |
18 | + */ | |
19 | + class TaxOptionLang extends ActiveRecord | |
20 | + { | |
21 | + | |
22 | + public static function primaryKey() | |
23 | + { | |
24 | + return [ | |
25 | + 'tax_option_id', | |
26 | + 'language_id', | |
27 | + ]; | |
28 | + } | |
29 | + | |
30 | + /** | |
31 | + * @inheritdoc | |
32 | + */ | |
33 | + public static function tableName() | |
34 | + { | |
35 | + return 'tax_option_lang'; | |
36 | + } | |
37 | + | |
38 | + public function behaviors() | |
39 | + { | |
40 | + return [ | |
41 | + 'slug' => [ | |
42 | + 'class' => 'common\behaviors\Slug', | |
43 | + 'inAttribute' => 'value', | |
44 | + ], | |
45 | + ]; | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * @inheritdoc | |
50 | + */ | |
51 | + public function rules() | |
52 | + { | |
53 | + return [ | |
54 | + [ | |
55 | + [ 'value' ], | |
56 | + 'required', | |
57 | + ], | |
58 | + [ | |
59 | + [ | |
60 | + 'value', | |
61 | + 'alias', | |
62 | + ], | |
63 | + 'string', | |
64 | + 'max' => 255, | |
65 | + ], | |
66 | + [ | |
67 | + [ | |
68 | + 'tax_option_id', | |
69 | + 'language_id', | |
70 | + ], | |
71 | + 'unique', | |
72 | + 'targetAttribute' => [ | |
73 | + 'tax_option_id', | |
74 | + 'language_id', | |
75 | + ], | |
76 | + 'message' => 'The combination of Tax Option ID and Language ID has already been taken.', | |
77 | + ], | |
78 | + [ | |
79 | + [ 'language_id' ], | |
80 | + 'exist', | |
81 | + 'skipOnError' => true, | |
82 | + 'targetClass' => Language::className(), | |
83 | + 'targetAttribute' => [ 'language_id' => 'id' ], | |
84 | + ], | |
85 | + [ | |
86 | + [ 'tax_option_id' ], | |
87 | + 'exist', | |
88 | + 'skipOnError' => true, | |
89 | + 'targetClass' => TaxOption::className(), | |
90 | + 'targetAttribute' => [ 'tax_option_id' => 'id' ], | |
91 | + ], | |
92 | + ]; | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * @inheritdoc | |
97 | + */ | |
98 | + public function attributeLabels() | |
99 | + { | |
100 | + return [ | |
101 | + 'tax_option_id' => Yii::t('app', 'Tax Option ID'), | |
102 | + 'language_id' => Yii::t('app', 'Language ID'), | |
103 | + 'value' => Yii::t('app', 'Value'), | |
104 | + 'alias' => Yii::t('app', 'Alias'), | |
105 | + ]; | |
106 | + } | |
107 | + | |
108 | + /** | |
109 | + * @return \yii\db\ActiveQuery | |
110 | + */ | |
111 | + public function getLanguage() | |
112 | + { | |
113 | + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]); | |
114 | + } | |
115 | + | |
116 | + /** | |
117 | + * @return \yii\db\ActiveQuery | |
118 | + */ | |
119 | + public function getTaxOption() | |
120 | + { | |
121 | + return $this->hasOne(TaxOption::className(), [ 'id' => 'tax_option_id' ]); | |
122 | + } | |
123 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/models/TaxOptionSearch.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\models; | |
4 | + | |
5 | + use yii\base\Model; | |
6 | + use yii\data\ActiveDataProvider; | |
7 | + | |
8 | + /** | |
9 | + * TaxOptionSearch represents the model behind the search form about | |
10 | + * `artweb\artbox\ecommerce\models\TaxOption`. | |
11 | + */ | |
12 | + class TaxOptionSearch extends TaxOption | |
13 | + { | |
14 | + | |
15 | + public $value; | |
16 | + | |
17 | + public function behaviors() | |
18 | + { | |
19 | + $behaviors = parent::behaviors(); | |
20 | + if (isset( $behaviors[ 'language' ] )) { | |
21 | + unset( $behaviors[ 'language' ] ); | |
22 | + } | |
23 | + return $behaviors; | |
24 | + } | |
25 | + | |
26 | + /** | |
27 | + * @inheritdoc | |
28 | + */ | |
29 | + public function rules() | |
30 | + { | |
31 | + return [ | |
32 | + [ | |
33 | + [ 'value' ], | |
34 | + 'safe', | |
35 | + ], | |
36 | + [ | |
37 | + [ 'id' ], | |
38 | + 'integer', | |
39 | + ], | |
40 | + ]; | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * @inheritdoc | |
45 | + */ | |
46 | + public function scenarios() | |
47 | + { | |
48 | + // bypass scenarios() implementation in the parent class | |
49 | + return Model::scenarios(); | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * Creates data provider instance with search query applied | |
54 | + * | |
55 | + * @param array $params | |
56 | + * | |
57 | + * @return ActiveDataProvider | |
58 | + */ | |
59 | + public function search($params) | |
60 | + { | |
61 | + $query = TaxOption::find() | |
62 | + ->joinWith('lang'); | |
63 | + | |
64 | + $dataProvider = new ActiveDataProvider( | |
65 | + [ | |
66 | + 'query' => $query, | |
67 | + 'sort' => [ | |
68 | + 'attributes' => [ | |
69 | + 'id', | |
70 | + 'value' => [ | |
71 | + 'asc' => [ 'tax_option_lang.value' => SORT_ASC ], | |
72 | + 'desc' => [ 'tax_option_lang.value' => SORT_DESC ], | |
73 | + ], | |
74 | + ], | |
75 | + ], | |
76 | + ] | |
77 | + ); | |
78 | + | |
79 | + $this->load($params); | |
80 | + | |
81 | + // if (!$this->validate()) { | |
82 | + // return $dataProvider; | |
83 | + // } | |
84 | + | |
85 | + // grid filtering conditions | |
86 | + $query->andFilterWhere( | |
87 | + [ | |
88 | + 'id' => $this->id, | |
89 | + ] | |
90 | + ) | |
91 | + ->andFilterWhere( | |
92 | + [ | |
93 | + 'like', | |
94 | + 'tax_option_lang.value', | |
95 | + $this->value, | |
96 | + ] | |
97 | + ); | |
98 | + | |
99 | + return $dataProvider; | |
100 | + } | |
101 | + } | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/_form.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\widgets\LanguageForm; | |
4 | + use artweb\artbox\ecommerce\models\Brand; | |
5 | + use artweb\artbox\ecommerce\models\ProductLang; | |
6 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
7 | + use yii\db\ActiveQuery; | |
8 | + use yii\helpers\Html; | |
9 | + use yii\widgets\ActiveForm; | |
10 | + use yii\helpers\ArrayHelper; | |
11 | + use common\components\artboxtree\ArtboxTreeHelper; | |
12 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
13 | + use kartik\select2\Select2; | |
14 | + | |
15 | + /** | |
16 | + * @var yii\web\View $this | |
17 | + * @var artweb\artbox\ecommerce\models\Product $model | |
18 | + * @var ProductLang[] $modelLangs | |
19 | + * @var yii\widgets\ActiveForm $form | |
20 | + * @var ActiveQuery $groups | |
21 | + */ | |
22 | +?> | |
23 | + | |
24 | +<div class="product-form"> | |
25 | + | |
26 | + <?php $form = ActiveForm::begin( | |
27 | + [ | |
28 | + 'options' => [ 'enctype' => 'multipart/form-data' ], | |
29 | + ] | |
30 | + ); ?> | |
31 | + | |
32 | + <?= $form->field($model, 'is_top') | |
33 | + ->checkbox([ 'label' => 'ТОП' ]) ?> | |
34 | + <?= $form->field($model, 'is_new') | |
35 | + ->checkbox([ 'label' => 'Новинка' ]) ?> | |
36 | + <?= $form->field($model, 'is_discount') | |
37 | + ->checkbox([ 'label' => 'Акционный' ]) ?> | |
38 | + | |
39 | + <?= $form->field($model, 'video') | |
40 | + ->textarea(); ?> | |
41 | + | |
42 | + <?= $form->field($model, 'brand_id') | |
43 | + ->dropDownList( | |
44 | + ArrayHelper::map( | |
45 | + Brand::find() | |
46 | + ->with('lang') | |
47 | + ->all(), | |
48 | + 'id', | |
49 | + 'lang.title' | |
50 | + ), | |
51 | + [ | |
52 | + 'prompt' => Yii::t('product', 'Select brand'), | |
53 | + ] | |
54 | + ) ?> | |
55 | + | |
56 | + <?= $form->field($model, 'categories') | |
57 | + ->widget( | |
58 | + Select2::className(), | |
59 | + [ | |
60 | + 'data' => ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'id', 'lang.title'), | |
61 | + 'language' => 'ru', | |
62 | + 'options' => [ | |
63 | + 'placeholder' => Yii::t('product', 'Select categories'), | |
64 | + 'multiple' => true, | |
65 | + ], | |
66 | + 'pluginOptions' => [ | |
67 | + 'allowClear' => true, | |
68 | + ], | |
69 | + ] | |
70 | + ) ?> | |
71 | + | |
72 | + <?= $form->field($model, 'imagesUpload[]') | |
73 | + ->widget( | |
74 | + \kartik\file\FileInput::className(), | |
75 | + [ | |
76 | + 'language' => 'ru', | |
77 | + 'options' => [ | |
78 | + 'accept' => 'image/*', | |
79 | + 'multiple' => true, | |
80 | + ], | |
81 | + 'pluginOptions' => [ | |
82 | + 'allowedFileExtensions' => [ | |
83 | + 'jpg', | |
84 | + 'gif', | |
85 | + 'png', | |
86 | + ], | |
87 | + 'initialPreview' => !empty( $model->imagesHTML ) ? $model->imagesHTML : [], | |
88 | + 'initialPreviewConfig' => $model->imagesConfig, | |
89 | + 'overwriteInitial' => false, | |
90 | + 'showRemove' => false, | |
91 | + 'showUpload' => false, | |
92 | + 'uploadAsync' => !empty( $model->id ), | |
93 | + 'previewFileType' => 'image', | |
94 | + ], | |
95 | + ] | |
96 | + ); ?> | |
97 | + | |
98 | + <?php if (!empty( $groups )) { | |
99 | + foreach ($groups->with('lang') | |
100 | + ->all() as $group) { | |
101 | + /** | |
102 | + * @var TaxGroup $group | |
103 | + */ | |
104 | + echo $form->field($model, 'options') | |
105 | + ->checkboxList( | |
106 | + ArrayHelper::map( | |
107 | + $group->getOptions() | |
108 | + ->with('lang') | |
109 | + ->all(), | |
110 | + 'id', | |
111 | + 'lang.value' | |
112 | + ), | |
113 | + [ | |
114 | + 'multiple' => true, | |
115 | + 'unselect' => NULL, | |
116 | + ] | |
117 | + ) | |
118 | + ->label($group->lang->title); | |
119 | + } | |
120 | + } | |
121 | + ?> | |
122 | + | |
123 | + <hr> | |
124 | + | |
125 | + <?= LanguageForm::widget( | |
126 | + [ | |
127 | + 'modelLangs' => $modelLangs, | |
128 | + 'formView' => '@common/modules/product/views/manage/_form_language', | |
129 | + 'form' => $form, | |
130 | + ] | |
131 | + ) ?> | |
132 | + | |
133 | + <div class="form-group"> | |
134 | + <?= Html::submitButton( | |
135 | + $model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), | |
136 | + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ] | |
137 | + ) ?> | |
138 | + </div> | |
139 | + | |
140 | + <?php ActiveForm::end(); ?> | |
141 | + | |
142 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/_form_language.php | |
1 | +<?php | |
2 | + use common\modules\language\models\Language; | |
3 | + use artweb\artbox\ecommerce\models\ProductLang; | |
4 | + use mihaildev\ckeditor\CKEditor; | |
5 | + use mihaildev\elfinder\ElFinder; | |
6 | + use yii\web\View; | |
7 | + use yii\widgets\ActiveForm; | |
8 | + | |
9 | + /** | |
10 | + * @var ProductLang $model_lang | |
11 | + * @var Language $language | |
12 | + * @var ActiveForm $form | |
13 | + * @var View $this | |
14 | + */ | |
15 | +?> | |
16 | +<?= $form->field($model_lang, '[' . $language->id . ']title') | |
17 | + ->textInput([ 'maxlength' => true ]); ?> | |
18 | +<?= $form->field($model_lang, '[' . $language->id . ']alias') | |
19 | + ->textInput([ 'maxlength' => true ]); ?> | |
20 | +<?= $form->field($model_lang, '[' . $language->id . ']description') | |
21 | + ->widget(CKEditor::className(), [ | |
22 | + 'editorOptions' => ElFinder::ckeditorOptions('elfinder', [ | |
23 | + 'preset' => 'full', | |
24 | + 'inline' => false, | |
25 | + 'filebrowserUploadUrl' => Yii::$app->getUrlManager() | |
26 | + ->createUrl('file/uploader/images-upload'), | |
27 | + ]), | |
28 | + ]) ?> | |
0 | 29 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/create.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Product; | |
4 | + use artweb\artbox\ecommerce\models\ProductLang; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var Product $model | |
11 | + * @var ProductLang[] $modelLangs | |
12 | + */ | |
13 | + | |
14 | + $this->title = Yii::t('product', 'Create Product'); | |
15 | + $this->params[ 'breadcrumbs' ][] = [ | |
16 | + 'label' => Yii::t('product', 'Products'), | |
17 | + 'url' => [ 'index' ], | |
18 | + ]; | |
19 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
20 | +?> | |
21 | +<div class="product-create"> | |
22 | + | |
23 | + <h1><?= Html::encode($this->title) ?></h1> | |
24 | + | |
25 | + <?= $this->render('_form', [ | |
26 | + 'model' => $model, | |
27 | + 'modelLangs' => $modelLangs, | |
28 | + ]) ?> | |
29 | + | |
30 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/export-process.php | |
1 | +<?php | |
2 | + /** | |
3 | + * @var View $this | |
4 | + */ | |
5 | + | |
6 | + use yii\web\View; | |
7 | + | |
8 | +?> | |
9 | +<?php | |
10 | + $this->registerJs("var in_process=true; | |
11 | + var count=1; | |
12 | + var filename = null; | |
13 | + | |
14 | + doExport(0,filename); | |
15 | + | |
16 | + function doExport(from,filename) { | |
17 | + from = typeof(from) != 'undefined' ? from : 0; | |
18 | + | |
19 | + $.ajax({ | |
20 | + method: 'get', | |
21 | + url: '" . Yii::$app->request->baseUrl . '/product/manage/export-process' . "', | |
22 | + data: { | |
23 | + from:from, | |
24 | + filename: filename | |
25 | + }, | |
26 | + dataType: 'json', | |
27 | + success: function(data){ | |
28 | + | |
29 | + var per = Math.round(100*data.from/data.totalsize)+'%'; | |
30 | + $('#progressbar div').css({width: per}); | |
31 | + | |
32 | + if(data != false && !data.end) | |
33 | + { | |
34 | + doExport(data.from,data.filename); | |
35 | + } | |
36 | + else | |
37 | + { | |
38 | + console.log(data.link); | |
39 | + $(progressbar).hide('fast'); | |
40 | + $('#result_link').attr('href', data.link).removeClass('hidden'); | |
41 | + in_process = false; | |
42 | + } | |
43 | + }, | |
44 | + error: function(xhr, status, errorThrown) { | |
45 | + } | |
46 | + }); | |
47 | + }"); | |
48 | +?> | |
49 | + | |
50 | +<!--<script>--> | |
51 | +<!-- var in_process=true;--> | |
52 | +<!-- var count=1;--> | |
53 | +<!-- var filename = null;--> | |
54 | +<!-- --> | |
55 | +<!-- doExport(0,filename);--> | |
56 | +<!-- --> | |
57 | +<!-- function doExport(from,filename) {--> | |
58 | +<!-- from = typeof(from) != 'undefined' ? from : 0;--> | |
59 | +<!-- --> | |
60 | +<!-- $.ajax({--> | |
61 | +<!-- method: 'get',--> | |
62 | +<!-- url: '".Yii::$app->request->baseUrl .'/product/manage/export-process'."',--> | |
63 | +<!-- data: {--> | |
64 | +<!-- from:from,--> | |
65 | +<!-- filename: filename--> | |
66 | +<!-- },--> | |
67 | +<!-- dataType: 'json',--> | |
68 | +<!-- success: function(data){--> | |
69 | +<!-- --> | |
70 | +<!-- var per = Math.round(100*data.from/data.totalsize)+'%';--> | |
71 | +<!-- $('#progressbar div').css({width: per});--> | |
72 | +<!-- --> | |
73 | +<!-- if(data != false && !data.end)--> | |
74 | +<!-- {--> | |
75 | +<!-- doExport(data.from,data.filename);--> | |
76 | +<!-- }--> | |
77 | +<!-- else--> | |
78 | +<!-- {--> | |
79 | +<!-- console.log(data.link);--> | |
80 | +<!-- progressbar.hide('fast');--> | |
81 | +<!-- in_process = false;--> | |
82 | +<!-- }--> | |
83 | +<!-- },--> | |
84 | +<!-- error: function(xhr, status, errorThrown) {--> | |
85 | +<!-- }--> | |
86 | +<!-- });--> | |
87 | +<!-- }--> | |
88 | +<!--</script>--> | |
89 | + | |
90 | +<div class="product-import-process-form"> | |
91 | + <h1>Экспорт данных товаров</h1> | |
92 | + | |
93 | + <?= \yii\jui\ProgressBar::widget([ | |
94 | + 'clientOptions' => [ | |
95 | + 'value' => 100, | |
96 | + 'label' => '', | |
97 | + ], | |
98 | + 'options' => [ | |
99 | + 'id' => 'progressbar', | |
100 | + ], | |
101 | + ]); ?> | |
102 | + <ul id="process-result"></ul> | |
103 | + <a id="result_link" href="" class="hidden"><?php echo \Yii::t('app', 'Get File'); ?></a> | |
104 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/export.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\models\Language; | |
4 | + use artweb\artbox\ecommerce\models\Export; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + use yii\widgets\ActiveForm; | |
8 | + | |
9 | + /** | |
10 | + * @var View $this | |
11 | + * @var Export $model | |
12 | + */ | |
13 | +?> | |
14 | + | |
15 | +<div class="product-import-form"> | |
16 | + <?php $form = ActiveForm::begin([ | |
17 | + 'enableClientValidation' => false, | |
18 | + 'options' => [ 'enctype' => 'multipart/form-data' ], | |
19 | + ]); ?> | |
20 | + | |
21 | + <?php if($model->errors) : ?> | |
22 | + <div class="error"> | |
23 | + <?= implode("<br>\n", $model->errors); ?> | |
24 | + </div> | |
25 | + <?php endif ?> | |
26 | + | |
27 | + <?php if($model->output) : ?> | |
28 | + <h2>Лог операции</h2> | |
29 | + <div class="success" style="height: 10em;overflow: auto;border: 1px solid #000"> | |
30 | + <?= implode("<br>\n", $model->output); ?> | |
31 | + </div> | |
32 | + <?php endif ?> | |
33 | + | |
34 | + <?= $form->field($model, 'lang') | |
35 | + ->dropDownList(Language::find() | |
36 | + ->select([ | |
37 | + 'name', | |
38 | + 'id', | |
39 | + ]) | |
40 | + ->where([ 'status' => 1 ]) | |
41 | + ->orderBy([ 'default' => SORT_DESC ]) | |
42 | + ->asArray() | |
43 | + ->indexBy('id') | |
44 | + ->column()) ?> | |
45 | + | |
46 | + <div class="form-group"> | |
47 | + <?= Html::submitButton(Yii::t('product', 'Export'), [ 'class' => 'btn btn-success' ]) ?> | |
48 | + </div> | |
49 | + | |
50 | + <?php ActiveForm::end(); ?> | |
51 | +</div> | |
0 | 52 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/import-process.php | |
1 | +<?php | |
2 | + /** | |
3 | + * @var View $this | |
4 | + * @var string $method | |
5 | + */ | |
6 | + use yii\web\View; | |
7 | + | |
8 | + $this->registerJs(" | |
9 | +var in_process=false; | |
10 | + var count=1; | |
11 | + | |
12 | + in_process=true; | |
13 | + | |
14 | + doImport(); | |
15 | + | |
16 | + function doImport(from) { | |
17 | + from = typeof(from) != 'undefined' ? from : 0; | |
18 | + console.log('go', from); | |
19 | + $.ajax({ | |
20 | + url: '" . \Yii::$app->request->baseUrl . '/product/manage/' . $method . "', | |
21 | + data: {from:from}, | |
22 | + dataType: 'json', | |
23 | + success: function(data){ | |
24 | + for(var key in data.items) | |
25 | + { | |
26 | + $('ul#process-result').prepend('<li>'+ data.items[key] +'</li>'); | |
27 | + count++; | |
28 | + } | |
29 | + | |
30 | + var per = Math.round(100*data.from/data.totalsize)+'%'; | |
31 | + $('#progressbar div').css({width: per}); | |
32 | + | |
33 | + if(data != false && !data.end) | |
34 | + { | |
35 | + doImport(data.from); | |
36 | + } | |
37 | + else | |
38 | + { | |
39 | + $('ul#process-result').prepend('<li>Импорт цен успешно завершен!</li>'); | |
40 | + progressbar.hide('fast'); | |
41 | + in_process = false; | |
42 | + } | |
43 | + }, | |
44 | + error: function(xhr, status, errorThrown) { | |
45 | + } | |
46 | + }); | |
47 | + } | |
48 | +"); | |
49 | + //?> | |
50 | + | |
51 | +<div class="product-import-process-form"> | |
52 | + <h1>Импорт <?= $method == 'prices' ? 'цен' : 'данных' ?> товаров</h1> | |
53 | + | |
54 | + <?= \yii\jui\ProgressBar::widget([ | |
55 | + 'clientOptions' => [ | |
56 | + 'value' => 100, | |
57 | + 'label' => '', | |
58 | + ], | |
59 | + 'options' => [ | |
60 | + 'id' => 'progressbar', | |
61 | + ], | |
62 | + ]); ?> | |
63 | + <ul id="process-result"></ul> | |
64 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/import.php | |
1 | +<?php | |
2 | + | |
3 | + /** | |
4 | + * @var Import $model | |
5 | + * @var array $languages | |
6 | + */ | |
7 | + | |
8 | + use artweb\artbox\ecommerce\models\Import; | |
9 | + use yii\helpers\Html; | |
10 | + use yii\widgets\ActiveForm; | |
11 | + | |
12 | +?> | |
13 | + | |
14 | +<div class="product-import-form"> | |
15 | + <?php $form = ActiveForm::begin([ | |
16 | + 'enableClientValidation' => false, | |
17 | + 'options' => [ 'enctype' => 'multipart/form-data' ], | |
18 | + ]); ?> | |
19 | + | |
20 | + <?php if($model->errors) : ?> | |
21 | + <div class="error"> | |
22 | + <?= implode("<br>\n", $model->errors); ?> | |
23 | + </div> | |
24 | + <?php endif ?> | |
25 | + | |
26 | + <?php if($model->output) : ?> | |
27 | + <h2>Лог операции</h2> | |
28 | + <div class="success" style="height: 10em;overflow: auto;border: 1px solid #000"> | |
29 | + <?= implode("<br>\n", $model->output); ?> | |
30 | + </div> | |
31 | + <?php endif ?> | |
32 | + | |
33 | + <?= $form->field($model, 'type') | |
34 | + ->radioList([ | |
35 | + 'products' => Yii::t('product', 'Load products'), | |
36 | + 'prices' => Yii::t('product', 'Load prices'), | |
37 | + ]); ?> | |
38 | + | |
39 | + <?= $form->field($model, 'lang') | |
40 | + ->dropDownList($languages); ?> | |
41 | + | |
42 | + <?= $form->field($model, 'file') | |
43 | + ->fileInput([ 'multiple' => false, ]) ?> | |
44 | + | |
45 | + <?php /*= $form->field($model, 'file')->widget(\kartik\file\FileInput::classname(), [ | |
46 | + 'language' => 'ru', | |
47 | + 'options' => [ | |
48 | + 'multiple' => false, | |
49 | + ], | |
50 | + 'pluginOptions' => [ | |
51 | + 'allowedFileExtensions' => ['csv'], | |
52 | + 'overwriteInitial' => true, | |
53 | + 'showRemove' => false, | |
54 | + 'showUpload' => false, | |
55 | + ], | |
56 | + ])*/ ?> | |
57 | + | |
58 | + <div class="form-group"> | |
59 | + <?= Html::submitButton(Yii::t('product', 'Import'), [ 'class' => 'btn btn-primary' ]) ?> | |
60 | + </div> | |
61 | + | |
62 | + <?php ActiveForm::end(); ?> | |
63 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/index.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Brand; | |
4 | + use artweb\artbox\ecommerce\models\Category; | |
5 | + use artweb\artbox\ecommerce\models\Product; | |
6 | + use artweb\artbox\ecommerce\models\ProductSearch; | |
7 | + use yii\data\ActiveDataProvider; | |
8 | + use yii\helpers\Html; | |
9 | + use yii\grid\GridView; | |
10 | + use kartik\select2\Select2; | |
11 | + use common\components\artboxtree\ArtboxTreeHelper; | |
12 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
13 | + use yii\web\View; | |
14 | + | |
15 | + /** | |
16 | + * @var View $this | |
17 | + * @var ProductSearch $searchModel | |
18 | + * @var ActiveDataProvider $dataProvider | |
19 | + */ | |
20 | + $this->title = Yii::t('product', 'Products'); | |
21 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
22 | +?> | |
23 | +<div class="product-index"> | |
24 | + | |
25 | + <h1><?= Html::encode($this->title) ?></h1> | |
26 | + | |
27 | + <p> | |
28 | + <?= Html::a(Yii::t('product', 'Create Product'), [ 'create' ], [ 'class' => 'btn btn-success' ]) ?> | |
29 | + </p> | |
30 | + <?= GridView::widget( | |
31 | + [ | |
32 | + 'dataProvider' => $dataProvider, | |
33 | + 'filterModel' => $searchModel, | |
34 | + 'columns' => [ | |
35 | + 'id', | |
36 | + [ | |
37 | + 'attribute' => 'productName', | |
38 | + 'value' => 'lang.title', | |
39 | + ], | |
40 | + [ | |
41 | + 'label' => Yii::t('product', 'Brand'), | |
42 | + 'attribute' => 'brand_id', | |
43 | + 'value' => 'brand.lang.title', | |
44 | + 'filter' => Select2::widget( | |
45 | + [ | |
46 | + 'model' => $searchModel, | |
47 | + 'attribute' => 'brand_id', | |
48 | + 'data' => Brand::find() | |
49 | + ->joinWith('lang') | |
50 | + ->select( | |
51 | + [ | |
52 | + 'brand_lang.title', | |
53 | + 'brand.id', | |
54 | + ] | |
55 | + ) | |
56 | + ->asArray() | |
57 | + ->indexBy('id') | |
58 | + ->column(), | |
59 | + 'language' => 'ru', | |
60 | + 'options' => [ | |
61 | + 'placeholder' => Yii::t('product', 'Select brand'), | |
62 | + 'multiple' => false, | |
63 | + ], | |
64 | + 'pluginOptions' => [ | |
65 | + 'allowClear' => true, | |
66 | + ], | |
67 | + ] | |
68 | + ), | |
69 | + ], | |
70 | + [ | |
71 | + 'label' => Yii::t('product', 'Category'), | |
72 | + 'attribute' => 'categoryId', | |
73 | + 'value' => function ($model) { | |
74 | + /** | |
75 | + * @var Product $model | |
76 | + */ | |
77 | + $categories = []; | |
78 | + foreach ($model->getCategories() | |
79 | + ->with('lang') | |
80 | + ->all() as $category) { | |
81 | + /** | |
82 | + * @var Category $category | |
83 | + */ | |
84 | + $categories[] = $category->lang->title; | |
85 | + } | |
86 | + return implode(", ", $categories); | |
87 | + }, | |
88 | + 'filter' => Select2::widget( | |
89 | + [ | |
90 | + 'model' => $searchModel, | |
91 | + 'attribute' => 'categoryId', | |
92 | + 'data' => ArtboxTreeHelper::treeMap( | |
93 | + ProductHelper::getCategories(), | |
94 | + 'id', | |
95 | + 'lang.title' | |
96 | + ), | |
97 | + 'language' => 'ru', | |
98 | + 'options' => [ | |
99 | + 'placeholder' => Yii::t('product', 'Select category'), | |
100 | + 'multiple' => false, | |
101 | + ], | |
102 | + 'pluginOptions' => [ | |
103 | + 'allowClear' => true, | |
104 | + ], | |
105 | + ] | |
106 | + ), | |
107 | + ], | |
108 | + [ | |
109 | + 'attribute' => 'variantCount', | |
110 | + 'value' => function ($model) { | |
111 | + /** | |
112 | + * @var Product $model | |
113 | + */ | |
114 | + return count($model->variants); | |
115 | + }, | |
116 | + ], | |
117 | + [ | |
118 | + 'class' => 'yii\grid\ActionColumn', | |
119 | + 'template' => '{items} {view} |{is_top} {is_new} {is_discount} | {update} {delete}', | |
120 | + 'buttons' => [ | |
121 | + 'is_top' => function ($url, $model) { | |
122 | + return Html::a( | |
123 | + '<span class="glyphicon glyphicon-star' . ( $model->is_top ? '' : '-empty' ) . '"></span>', | |
124 | + $url, | |
125 | + [ | |
126 | + 'title' => Yii::t('product', ( $model->is_top ? 'Set not is top' : 'Set is top' )), | |
127 | + ] | |
128 | + ); | |
129 | + }, | |
130 | + 'is_new' => function ($url, $model) { | |
131 | + return Html::a( | |
132 | + '<span class="glyphicon glyphicon-heart' . ( $model->is_new ? '' : '-empty' ) . '"></span>', | |
133 | + $url, | |
134 | + [ | |
135 | + 'title' => Yii::t('product', ( $model->is_new ? 'Set not is new' : 'Set is new' )), | |
136 | + ] | |
137 | + ); | |
138 | + }, | |
139 | + 'is_discount' => function ($url, $model) { | |
140 | + return Html::a( | |
141 | + '<span class="glyphicon glyphicon-tag' . ( $model->is_discount ? 's' : '' ) . '"></span>', | |
142 | + $url, | |
143 | + [ | |
144 | + 'title' => Yii::t( | |
145 | + 'product', | |
146 | + ( $model->is_discount ? 'Set not is promotion' : 'Set is promotion' ) | |
147 | + ), | |
148 | + ] | |
149 | + ); | |
150 | + }, | |
151 | + 'items' => function ($url, $model) { | |
152 | + return Html::a( | |
153 | + '<span class="glyphicon glyphicon-th-list"></span>', | |
154 | + $url, | |
155 | + [ | |
156 | + 'title' => Yii::t('product', 'Variants'), | |
157 | + ] | |
158 | + ); | |
159 | + }, | |
160 | + | |
161 | + ], | |
162 | + 'urlCreator' => function ($action, $model, $key, $index) { | |
163 | + /** | |
164 | + * @var Product $model | |
165 | + */ | |
166 | + switch ($action) { | |
167 | + case 'items': | |
168 | + return \yii\helpers\Url::to( | |
169 | + [ | |
170 | + '/product/variant', | |
171 | + 'product_id' => $model->id, | |
172 | + ] | |
173 | + ); | |
174 | + break; | |
175 | + case 'is_top': | |
176 | + return \yii\helpers\Url::to( | |
177 | + [ | |
178 | + 'manage/is_top', | |
179 | + 'id' => $model->id, | |
180 | + ] | |
181 | + ); | |
182 | + break; | |
183 | + case 'is_new': | |
184 | + return \yii\helpers\Url::to( | |
185 | + [ | |
186 | + 'manage/is_new', | |
187 | + 'id' => $model->id, | |
188 | + ] | |
189 | + ); | |
190 | + break; | |
191 | + case 'is_discount': | |
192 | + return \yii\helpers\Url::to( | |
193 | + [ | |
194 | + 'manage/is-discount', | |
195 | + 'id' => $model->id, | |
196 | + ] | |
197 | + ); | |
198 | + break; | |
199 | + case 'view': | |
200 | + return \yii\helpers\Url::to( | |
201 | + [ | |
202 | + 'manage/view', | |
203 | + 'id' => $model->id, | |
204 | + ] | |
205 | + ); | |
206 | + break; | |
207 | + case 'update': | |
208 | + return \yii\helpers\Url::to( | |
209 | + [ | |
210 | + 'manage/update', | |
211 | + 'id' => $model->id, | |
212 | + ] | |
213 | + ); | |
214 | + break; | |
215 | + case 'delete': | |
216 | + return \yii\helpers\Url::to( | |
217 | + [ | |
218 | + 'manage/delete', | |
219 | + 'id' => $model->id, | |
220 | + ] | |
221 | + ); | |
222 | + break; | |
223 | + default: | |
224 | + return ''; | |
225 | + break; | |
226 | + } | |
227 | + }, | |
228 | + ], | |
229 | + ], | |
230 | + ] | |
231 | + ); ?> | |
232 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/update.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Product; | |
4 | + use artweb\artbox\ecommerce\models\ProductLang; | |
5 | + use yii\db\ActiveQuery; | |
6 | + use yii\helpers\Html; | |
7 | + use yii\web\View; | |
8 | + | |
9 | + /** | |
10 | + * @var View $this | |
11 | + * @var Product $model | |
12 | + * @var ProductLang[] $modelLangs | |
13 | + * @var ActiveQuery $groups | |
14 | + */ | |
15 | + | |
16 | + $this->title = Yii::t('product', 'Update {modelClass}: ', [ | |
17 | + 'modelClass' => 'Product', | |
18 | + ]) . ' ' . $model->lang->title; | |
19 | + $this->params[ 'breadcrumbs' ][] = [ | |
20 | + 'label' => Yii::t('product', 'Products'), | |
21 | + 'url' => [ 'index' ], | |
22 | + ]; | |
23 | + $this->params[ 'breadcrumbs' ][] = [ | |
24 | + 'label' => $model->lang->title, | |
25 | + 'url' => [ | |
26 | + 'view', | |
27 | + 'id' => $model->id, | |
28 | + ], | |
29 | + ]; | |
30 | + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update'); | |
31 | +?> | |
32 | +<div class="product-update"> | |
33 | + | |
34 | + <h1><?= Html::encode($this->title) ?></h1> | |
35 | + | |
36 | + <?= $this->render('_form', [ | |
37 | + 'model' => $model, | |
38 | + 'modelLangs' => $modelLangs, | |
39 | + 'groups' => $groups, | |
40 | + ]) ?> | |
41 | + | |
42 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/manage/view.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Category; | |
4 | + use artweb\artbox\ecommerce\models\Product; | |
5 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
6 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
7 | + use yii\helpers\ArrayHelper; | |
8 | + use yii\helpers\Html; | |
9 | + use yii\web\View; | |
10 | + use yii\widgets\DetailView; | |
11 | + | |
12 | + /** | |
13 | + * @var View $this | |
14 | + * @var Product $model | |
15 | + * @var Category[] $categories | |
16 | + * @var TaxGroup[] $properties | |
17 | + * @var ProductVariant[] $variants | |
18 | + */ | |
19 | + | |
20 | + $this->title = $model->lang->title; | |
21 | + $this->params[ 'breadcrumbs' ][] = [ | |
22 | + 'label' => Yii::t('product', 'Products'), | |
23 | + 'url' => [ 'index' ], | |
24 | + ]; | |
25 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
26 | + $properties_string = ''; | |
27 | + foreach ($properties as $property) { | |
28 | + $property_list = ''; | |
29 | + foreach ($property->options as $option) { | |
30 | + $property_list .= Html::tag('li', $option->lang->value); | |
31 | + } | |
32 | + $properties_string .= Html::tag('p', $property->lang->title) . Html::tag('ul', $property_list); | |
33 | + } | |
34 | + $variants_string = ''; | |
35 | + foreach ($variants as $variant) { | |
36 | + $variants_string .= Html::a( | |
37 | + $variant->lang->title, | |
38 | + [ | |
39 | + '/product/variant/view', | |
40 | + 'id' => $variant->id, | |
41 | + ] | |
42 | + ) . '<br>'; | |
43 | + } | |
44 | +?> | |
45 | +<div class="product-view"> | |
46 | + | |
47 | + <h1><?= Html::encode($this->title) ?></h1> | |
48 | + | |
49 | + <p> | |
50 | + <?= Html::a( | |
51 | + Yii::t('product', 'Update'), | |
52 | + [ | |
53 | + 'update', | |
54 | + 'id' => $model->id, | |
55 | + ], | |
56 | + [ 'class' => 'btn btn-primary' ] | |
57 | + ) ?> | |
58 | + <?= Html::a( | |
59 | + Yii::t('product', 'Delete'), | |
60 | + [ | |
61 | + 'delete', | |
62 | + 'id' => $model->id, | |
63 | + ], | |
64 | + [ | |
65 | + 'class' => 'btn btn-danger', | |
66 | + 'data' => [ | |
67 | + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'), | |
68 | + 'method' => 'post', | |
69 | + ], | |
70 | + ] | |
71 | + ) ?> | |
72 | + <?= Html::a( | |
73 | + Yii::t('product', 'Variants'), | |
74 | + [ | |
75 | + '/product/variant/index', | |
76 | + 'product_id' => $model->id, | |
77 | + ], | |
78 | + [ 'class' => 'btn btn-info' ] | |
79 | + ) ?> | |
80 | + </p> | |
81 | + | |
82 | + <?= DetailView::widget( | |
83 | + [ | |
84 | + 'model' => $model, | |
85 | + 'attributes' => [ | |
86 | + 'id', | |
87 | + 'brand.lang.title', | |
88 | + [ | |
89 | + 'label' => \Yii::t('app', 'Categories'), | |
90 | + 'value' => implode('<br>', ArrayHelper::getColumn($categories, 'lang.title')), | |
91 | + 'format' => 'html', | |
92 | + ], | |
93 | + [ | |
94 | + 'attribute' => 'is_top', | |
95 | + 'value' => $model->is_top ? Html::tag( | |
96 | + 'span', | |
97 | + '', | |
98 | + [ 'class' => 'glyphicon glyphicon-ok' ] | |
99 | + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]), | |
100 | + 'format' => 'html', | |
101 | + ], | |
102 | + [ | |
103 | + 'attribute' => 'is_new', | |
104 | + 'value' => $model->is_new ? Html::tag( | |
105 | + 'span', | |
106 | + '', | |
107 | + [ 'class' => 'glyphicon glyphicon-ok' ] | |
108 | + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]), | |
109 | + 'format' => 'html', | |
110 | + ], | |
111 | + [ | |
112 | + 'attribute' => 'is_discount', | |
113 | + 'value' => $model->is_discount ? Html::tag( | |
114 | + 'span', | |
115 | + '', | |
116 | + [ 'class' => 'glyphicon glyphicon-ok' ] | |
117 | + ) : Html::tag('span', '', [ 'class' => 'glyphicon glyphicon-remove' ]), | |
118 | + 'format' => 'html', | |
119 | + ], | |
120 | + [ | |
121 | + 'attribute' => 'video', | |
122 | + 'format' => 'html', | |
123 | + ], | |
124 | + [ | |
125 | + 'label' => \Yii::t('app', 'Properties'), | |
126 | + 'value' => $properties_string, | |
127 | + 'format' => 'html', | |
128 | + ], | |
129 | + [ | |
130 | + 'label' => \Yii::t('app', 'Variants'), | |
131 | + 'value' => $variants_string, | |
132 | + 'format' => 'html', | |
133 | + ], | |
134 | + 'lang.description:html', | |
135 | + 'image.imageUrl:image', | |
136 | + ], | |
137 | + ] | |
138 | + ) ?> | |
139 | + | |
140 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/product-unit/_form.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\widgets\LanguageForm; | |
4 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
5 | + use artweb\artbox\ecommerce\models\ProductUnitLang; | |
6 | + use yii\helpers\Html; | |
7 | + use yii\web\View; | |
8 | + use yii\widgets\ActiveForm; | |
9 | + | |
10 | + /** | |
11 | + * @var View $this | |
12 | + * @var ProductUnit $model | |
13 | + * @var ProductUnitLang[] $modelLangs | |
14 | + * @var ActiveForm $form | |
15 | + */ | |
16 | +?> | |
17 | + | |
18 | +<div class="product-unit-form"> | |
19 | + | |
20 | + <?php $form = ActiveForm::begin(); ?> | |
21 | + | |
22 | + <?= $form->field($model, 'is_default') | |
23 | + ->checkbox() ?> | |
24 | + | |
25 | + <?= LanguageForm::widget([ | |
26 | + 'modelLangs' => $modelLangs, | |
27 | + 'form' => $form, | |
28 | + 'formView' => '@common/modules/product/views/product-unit/_form_language', | |
29 | + ]) ?> | |
30 | + | |
31 | + <div class="form-group"> | |
32 | + <?= Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]) ?> | |
33 | + </div> | |
34 | + | |
35 | + <?php ActiveForm::end(); ?> | |
36 | + | |
37 | +</div> | ... | ... |
artbox-ecommerce/views/product-unit/_form_language.php
0 → 100755
1 | +++ a/artbox-ecommerce/views/product-unit/_form_language.php | |
1 | +<?php | |
2 | + use common\modules\language\models\Language; | |
3 | + use artweb\artbox\ecommerce\models\ProductUnitLang; | |
4 | + use yii\web\View; | |
5 | + use yii\widgets\ActiveForm; | |
6 | + | |
7 | + /** | |
8 | + * @var ProductUnitLang $model_lang | |
9 | + * @var Language $language | |
10 | + * @var ActiveForm $form | |
11 | + * @var View $this | |
12 | + */ | |
13 | +?> | |
14 | +<?= $form->field($model_lang, '[' . $language->id . ']title') | |
15 | + ->textInput([ 'maxlength' => true ]); ?> | |
16 | +<?= $form->field($model_lang, '[' . $language->id . ']short') | |
17 | + ->textInput([ 'maxlength' => true ]); ?> | |
0 | 18 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/views/product-unit/create.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
4 | + use artweb\artbox\ecommerce\models\ProductUnitLang; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var ProductUnit $model | |
11 | + * @var ProductUnitLang[] $modelLangs | |
12 | + */ | |
13 | + | |
14 | + $this->title = Yii::t('product', 'Create Product Unit'); | |
15 | + $this->params[ 'breadcrumbs' ][] = [ | |
16 | + 'label' => Yii::t('product', 'Product Units'), | |
17 | + 'url' => [ 'index' ], | |
18 | + ]; | |
19 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
20 | +?> | |
21 | +<div class="product-unit-create"> | |
22 | + | |
23 | + <h1><?= Html::encode($this->title) ?></h1> | |
24 | + | |
25 | + <?= $this->render('_form', [ | |
26 | + 'model' => $model, | |
27 | + 'modelLangs' => $modelLangs, | |
28 | + ]) ?> | |
29 | + | |
30 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/product-unit/index.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\ProductUnitSearch; | |
4 | + use yii\data\ActiveDataProvider; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\grid\GridView; | |
7 | + use yii\web\View; | |
8 | + | |
9 | + /** | |
10 | + * @var View $this | |
11 | + * @var ProductUnitSearch $searchModel | |
12 | + * @var ActiveDataProvider $dataProvider | |
13 | + */ | |
14 | + | |
15 | + $this->title = Yii::t('product', 'Product Units'); | |
16 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
17 | +?> | |
18 | +<div class="product-unit-index"> | |
19 | + | |
20 | + <h1><?= Html::encode($this->title) ?></h1> | |
21 | + | |
22 | + <p> | |
23 | + <?= Html::a(Yii::t('product', 'Create Product Unit'), [ 'create' ], [ 'class' => 'btn btn-success' ]) ?> | |
24 | + </p> | |
25 | + <?= GridView::widget( | |
26 | + [ | |
27 | + 'dataProvider' => $dataProvider, | |
28 | + 'filterModel' => $searchModel, | |
29 | + 'columns' => [ | |
30 | + 'id', | |
31 | + [ | |
32 | + 'attribute' => 'is_default', | |
33 | + 'format' => 'boolean', | |
34 | + 'filter' => [ | |
35 | + \Yii::$app->formatter->asBoolean(false), | |
36 | + \Yii::$app->formatter->asBoolean(true), | |
37 | + ], | |
38 | + ], | |
39 | + [ | |
40 | + 'attribute' => 'title', | |
41 | + 'value' => 'lang.title', | |
42 | + ], | |
43 | + 'lang.short', | |
44 | + [ 'class' => 'yii\grid\ActionColumn' ], | |
45 | + ], | |
46 | + ] | |
47 | + ); ?> | |
48 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/product-unit/update.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
4 | + use artweb\artbox\ecommerce\models\ProductUnitLang; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var ProductUnit $model | |
11 | + * @var ProductUnitLang[] $modelLangs | |
12 | + */ | |
13 | + | |
14 | + $this->title = Yii::t('product', 'Update {modelClass}: ', [ | |
15 | + 'modelClass' => 'Product Unit', | |
16 | + ]) . $model->lang->title; | |
17 | + $this->params[ 'breadcrumbs' ][] = [ | |
18 | + 'label' => Yii::t('product', 'Product Units'), | |
19 | + 'url' => [ 'index' ], | |
20 | + ]; | |
21 | + $this->params[ 'breadcrumbs' ][] = [ | |
22 | + 'label' => $model->lang->title, | |
23 | + 'url' => [ | |
24 | + 'view', | |
25 | + 'id' => $model->id, | |
26 | + ], | |
27 | + ]; | |
28 | + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update'); | |
29 | +?> | |
30 | +<div class="product-unit-update"> | |
31 | + | |
32 | + <h1><?= Html::encode($this->title) ?></h1> | |
33 | + | |
34 | + <?= $this->render('_form', [ | |
35 | + 'model' => $model, | |
36 | + 'modelLangs' => $modelLangs, | |
37 | + ]) ?> | |
38 | + | |
39 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/product-unit/view.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
4 | + use yii\helpers\Html; | |
5 | + use yii\web\View; | |
6 | + use yii\widgets\DetailView; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var ProductUnit $model | |
11 | + */ | |
12 | + | |
13 | + $this->title = $model->lang->title; | |
14 | + $this->params[ 'breadcrumbs' ][] = [ | |
15 | + 'label' => Yii::t('product', 'Product Units'), | |
16 | + 'url' => [ 'index' ], | |
17 | + ]; | |
18 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
19 | +?> | |
20 | +<div class="product-unit-view"> | |
21 | + | |
22 | + <h1><?= Html::encode($this->title) ?></h1> | |
23 | + | |
24 | + <p> | |
25 | + <?= Html::a( | |
26 | + Yii::t('product', 'Update'), | |
27 | + [ | |
28 | + 'update', | |
29 | + 'id' => $model->id, | |
30 | + ], | |
31 | + [ 'class' => 'btn btn-primary' ] | |
32 | + ) ?> | |
33 | + <?= Html::a( | |
34 | + Yii::t('product', 'Delete'), | |
35 | + [ | |
36 | + 'delete', | |
37 | + 'id' => $model->id, | |
38 | + ], | |
39 | + [ | |
40 | + 'class' => 'btn btn-danger', | |
41 | + 'data' => [ | |
42 | + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'), | |
43 | + 'method' => 'post', | |
44 | + ], | |
45 | + ] | |
46 | + ) ?> | |
47 | + </p> | |
48 | + | |
49 | + <?= DetailView::widget( | |
50 | + [ | |
51 | + 'model' => $model, | |
52 | + 'attributes' => [ | |
53 | + 'id', | |
54 | + 'is_default:boolean', | |
55 | + 'lang.title', | |
56 | + 'lang.short', | |
57 | + ], | |
58 | + ] | |
59 | + ) ?> | |
60 | + | |
61 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-group/_form.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\widgets\LanguageForm; | |
4 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
5 | + use artweb\artbox\ecommerce\models\TaxGroupLang; | |
6 | + use yii\helpers\Html; | |
7 | + use yii\web\View; | |
8 | + use yii\widgets\ActiveForm; | |
9 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
10 | + use common\components\artboxtree\ArtboxTreeHelper; | |
11 | + | |
12 | + /** | |
13 | + * @var View $this | |
14 | + * @var TaxGroup $model | |
15 | + * @var TaxGroupLang[] $modelLangs | |
16 | + * @var ActiveForm $form | |
17 | + */ | |
18 | +?> | |
19 | + | |
20 | +<div class="tax-group-form"> | |
21 | + | |
22 | + <?php $form = ActiveForm::begin([ 'options' => [ 'enctype' => 'multipart/form-data' ] ]); ?> | |
23 | + | |
24 | + <?= $form->field($model, 'categories') | |
25 | + ->dropDownList(ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'id', 'lang.title'), [ | |
26 | + 'multiple' => true, | |
27 | + ]) | |
28 | + ->label('Use in the following categories') ?> | |
29 | + | |
30 | + <?= $form->field($model, 'is_filter') | |
31 | + ->checkbox() ?> | |
32 | + | |
33 | + <?= $form->field($model, 'display') | |
34 | + ->checkbox() ?> | |
35 | + | |
36 | + <?= $form->field($model, 'is_menu') | |
37 | + ->checkbox() ?> | |
38 | + | |
39 | + <?= $form->field($model, 'sort') | |
40 | + ->textInput() ?> | |
41 | + | |
42 | + <?php | |
43 | + echo LanguageForm::widget([ | |
44 | + 'modelLangs' => $modelLangs, | |
45 | + 'formView' => '@common/modules/rubrication/views/tax-group/_form_language', | |
46 | + 'form' => $form, | |
47 | + ]); | |
48 | + ?> | |
49 | + | |
50 | + <div class="form-group"> | |
51 | + <?= Html::submitButton($model->isNewRecord ? Yii::t('rubrication', 'Create') : Yii::t('rubrication', 'Update'), [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ]) ?> | |
52 | + </div> | |
53 | + | |
54 | + <?php ActiveForm::end(); ?> | |
55 | + | |
56 | +</div> | ... | ... |
artbox-ecommerce/views/tax-group/_form_language.php
0 → 100755
1 | +++ a/artbox-ecommerce/views/tax-group/_form_language.php | |
1 | +<?php | |
2 | + use common\modules\language\models\Language; | |
3 | + use artweb\artbox\ecommerce\models\TaxGroupLang; | |
4 | + use yii\web\View; | |
5 | + use yii\widgets\ActiveForm; | |
6 | + | |
7 | + /** | |
8 | + * @var TaxGroupLang $model_lang | |
9 | + * @var Language $language | |
10 | + * @var ActiveForm $form | |
11 | + * @var View $this | |
12 | + */ | |
13 | +?> | |
14 | +<?= $form->field($model_lang, '[' . $language->id . ']title') | |
15 | + ->textInput([ 'maxlength' => true ]); ?> | |
16 | +<?= $form->field($model_lang, '[' . $language->id . ']alias') | |
17 | + ->textInput([ 'maxlength' => true ]); ?> | |
18 | +<?= $form->field($model_lang, '[' . $language->id . ']description') | |
19 | + ->textarea([ 'rows' => 6 ]) ?> | |
0 | 20 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-group/create.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxGroupLang; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var TaxGroup $model | |
11 | + * @var TaxGroupLang[] $modelLangs | |
12 | + */ | |
13 | + $this->title = Yii::t('rubrication', 'Create Tax Group'); | |
14 | + $this->params[ 'breadcrumbs' ][] = [ | |
15 | + 'label' => Yii::t('rubrication', 'Tax Groups'), | |
16 | + 'url' => [ 'index' ], | |
17 | + ]; | |
18 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
19 | +?> | |
20 | +<div class="tax-group-create"> | |
21 | + | |
22 | + <h1><?= Html::encode($this->title) ?></h1> | |
23 | + | |
24 | + <?= $this->render('_form', [ | |
25 | + 'model' => $model, | |
26 | + 'modelLangs' => $modelLangs, | |
27 | + ]) ?> | |
28 | + | |
29 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-group/index.php | |
1 | +<?php | |
2 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
3 | + use artweb\artbox\ecommerce\models\TaxGroupSearch; | |
4 | + use yii\data\ActiveDataProvider; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\grid\GridView; | |
7 | + use yii\helpers\Url; | |
8 | + use yii\web\View; | |
9 | + | |
10 | + /** | |
11 | + * @var View $this | |
12 | + * @var integer $level | |
13 | + * @var ActiveDataProvider $dataProvider | |
14 | + * @var TaxGroupSearch $searchModel | |
15 | + * @var TaxGroup $model | |
16 | + */ | |
17 | + | |
18 | + $this->title = $level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'); | |
19 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
20 | +?> | |
21 | + | |
22 | +<div class="tax-group-index"> | |
23 | + | |
24 | + <h1><?= Html::encode($this->title) ?></h1> | |
25 | + <p> | |
26 | + <?= Html::a( | |
27 | + Yii::t('rubrication', 'Create Group'), | |
28 | + Url::to( | |
29 | + [ | |
30 | + '/rubrication/tax-group/create', | |
31 | + 'level' => $level, | |
32 | + ] | |
33 | + ), | |
34 | + [ 'class' => 'btn btn-success' ] | |
35 | + ) ?> | |
36 | + </p> | |
37 | + | |
38 | + <?= GridView::widget( | |
39 | + [ | |
40 | + 'dataProvider' => $dataProvider, | |
41 | + 'filterModel' => $searchModel, | |
42 | + 'columns' => [ | |
43 | + [ 'class' => 'yii\grid\SerialColumn' ], | |
44 | + 'id', | |
45 | + [ | |
46 | + 'attribute' => 'is_filter', | |
47 | + 'format' => 'boolean', | |
48 | + 'filter' => \Yii::$app->formatter->booleanFormat, | |
49 | + ], | |
50 | + [ | |
51 | + 'attribute' => 'groupName', | |
52 | + 'value' => 'lang.title', | |
53 | + ], | |
54 | + [ | |
55 | + 'label' => \Yii::t('rubrication', 'Options count'), | |
56 | + 'value' => function ($model) { | |
57 | + /** | |
58 | + * @var TaxGroup $model | |
59 | + */ | |
60 | + return count($model->options); | |
61 | + }, | |
62 | + ], | |
63 | + [ | |
64 | + 'label' => \Yii::t('rubrication', 'Categories count'), | |
65 | + 'value' => function ($model) { | |
66 | + /** | |
67 | + * @var TaxGroup $model | |
68 | + */ | |
69 | + return count($model->categories); | |
70 | + }, | |
71 | + ], | |
72 | + [ | |
73 | + 'class' => 'yii\grid\ActionColumn', | |
74 | + 'template' => '{update} {options} {delete}', | |
75 | + 'buttons' => [ | |
76 | + 'options' => function ($url, $model) { | |
77 | + return Html::a( | |
78 | + '<span class="glyphicon glyphicon-th-list"></span>', | |
79 | + $url, | |
80 | + [ | |
81 | + 'title' => Yii::t('rubrication', 'Options'), | |
82 | + ] | |
83 | + ); | |
84 | + }, | |
85 | + ], | |
86 | + 'urlCreator' => function ($action, $model, $key, $index) use ($level) { | |
87 | + if ($action === 'options') { | |
88 | + $url = '/admin/rubrication/tax-option?group=' . $model->id; | |
89 | + return $url; | |
90 | + } elseif ($action === 'update') { | |
91 | + $url = Url::to( | |
92 | + [ | |
93 | + '/rubrication/tax-group/update', | |
94 | + 'level' => $level, | |
95 | + 'id' => $model->id, | |
96 | + ] | |
97 | + ); | |
98 | + return $url; | |
99 | + } elseif ($action === 'delete') { | |
100 | + $url = Url::to( | |
101 | + [ | |
102 | + '/rubrication/tax-group/delete', | |
103 | + 'level' => $level, | |
104 | + 'id' => $model->id, | |
105 | + ] | |
106 | + ); | |
107 | + return $url; | |
108 | + } | |
109 | + return ''; | |
110 | + }, | |
111 | + ], | |
112 | + ], | |
113 | + ] | |
114 | + ); ?> | |
115 | +</div> | |
116 | + | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-group/update.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxGroupLang; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + | |
8 | + /** | |
9 | + * @var View $this | |
10 | + * @var TaxGroup $model | |
11 | + * @var TaxGroupLang[] $modelLangs | |
12 | + * @var int $level | |
13 | + */ | |
14 | + | |
15 | + $this->title = Yii::t('rubrication', 'Update {modelClass}: ', [ | |
16 | + 'modelClass' => 'Tax Group', | |
17 | + ]) . ' ' . $model->lang->title; | |
18 | + $this->params[ 'breadcrumbs' ][] = [ | |
19 | + 'label' => $level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'), | |
20 | + 'url' => [ | |
21 | + 'index', | |
22 | + 'level' => $level, | |
23 | + ], | |
24 | + ]; | |
25 | + $this->params[ 'breadcrumbs' ][] = Yii::t('rubrication', 'Update'); | |
26 | +?> | |
27 | +<div class="tax-group-update"> | |
28 | + | |
29 | + <h1><?= Html::encode($this->title) ?></h1> | |
30 | + | |
31 | + <?= $this->render('_form', [ | |
32 | + 'model' => $model, | |
33 | + 'modelLangs' => $modelLangs, | |
34 | + ]) ?> | |
35 | + | |
36 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-group/view.php | |
1 | +<?php | |
2 | + | |
3 | + use yii\helpers\Html; | |
4 | + use yii\widgets\DetailView; | |
5 | + | |
6 | + /* @var $this yii\web\View */ | |
7 | + /* @var $model artweb\artbox\ecommerce\models\TaxGroup */ | |
8 | + | |
9 | + $this->title = $model->id; | |
10 | + $this->params[ 'breadcrumbs' ][] = [ | |
11 | + 'label' => Yii::t('rubrication', 'Tax Groups'), | |
12 | + 'url' => [ 'index' ], | |
13 | + ]; | |
14 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
15 | +?> | |
16 | +<div class="tax-group-view"> | |
17 | + | |
18 | + <h1><?= Html::encode($this->title) ?></h1> | |
19 | + | |
20 | + <p> | |
21 | + <?= Html::a( | |
22 | + Yii::t('rubrication', 'Update'), | |
23 | + [ | |
24 | + 'update', | |
25 | + 'id' => $model->id, | |
26 | + ], | |
27 | + [ 'class' => 'btn btn-primary' ] | |
28 | + ) ?> | |
29 | + <?= Html::a( | |
30 | + Yii::t('rubrication', 'Delete'), | |
31 | + [ | |
32 | + 'delete', | |
33 | + 'id' => $model->id, | |
34 | + ], | |
35 | + [ | |
36 | + 'class' => 'btn btn-danger', | |
37 | + 'data' => [ | |
38 | + 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'), | |
39 | + 'method' => 'post', | |
40 | + ], | |
41 | + ] | |
42 | + ) ?> | |
43 | + <?= Html::a( | |
44 | + Yii::t('rubrication', 'Create Option'), | |
45 | + [ 'tax-option/create?group=' . $model->id ], | |
46 | + [ 'class' => 'btn btn-success' ] | |
47 | + ) ?> | |
48 | + </p> | |
49 | + | |
50 | + <?= DetailView::widget( | |
51 | + [ | |
52 | + 'model' => $model, | |
53 | + 'attributes' => [ | |
54 | + 'id', | |
55 | + 'is_filter:boolean', | |
56 | + ], | |
57 | + ] | |
58 | + ) ?> | |
59 | + | |
60 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-option/_form.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\widgets\LanguageForm; | |
4 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
5 | + use artweb\artbox\ecommerce\models\TaxOptionLang; | |
6 | + use yii\helpers\ArrayHelper; | |
7 | + use yii\helpers\Html; | |
8 | + use yii\widgets\ActiveForm; | |
9 | + use artweb\artbox\ecommerce\models\TaxOption; | |
10 | + | |
11 | + /** | |
12 | + * @var yii\web\View $this | |
13 | + * @var artweb\artbox\ecommerce\models\TaxOption $model | |
14 | + * @var yii\widgets\ActiveForm $form | |
15 | + * @var TaxGroup $group | |
16 | + * @var TaxOptionLang[] $modelLangs | |
17 | + */ | |
18 | +?> | |
19 | + | |
20 | +<div class="tax-option-form"> | |
21 | + | |
22 | + <?php $form = ActiveForm::begin([ 'options' => [ 'enctype' => 'multipart/form-data' ] ]); ?> | |
23 | + <?php if (empty( $group->id )) : ?> | |
24 | + <?= $form->field($model, 'tax_group_id') | |
25 | + ->dropDownList( | |
26 | + ArrayHelper::map( | |
27 | + TaxOption::find() | |
28 | + ->all(), | |
29 | + 'tax_group_id', | |
30 | + 'tax_group_id' | |
31 | + ), | |
32 | + [ | |
33 | + 'prompt' => Yii::t('rubrication', 'Select group'), | |
34 | + ] | |
35 | + ) ?> | |
36 | + <?php else : ?> | |
37 | + <?= $form->field($model, 'tax_group_id') | |
38 | + ->hiddenInput() | |
39 | + ->label('') ?> | |
40 | + <?php endif ?> | |
41 | + | |
42 | + <?= $form->field($model, 'image') | |
43 | + ->widget( | |
44 | + \kartik\file\FileInput::className(), | |
45 | + [ | |
46 | + 'language' => 'ru', | |
47 | + 'options' => [ | |
48 | + 'accept' => 'image/*', | |
49 | + 'multiple' => false, | |
50 | + ], | |
51 | + 'pluginOptions' => [ | |
52 | + 'allowedFileExtensions' => [ | |
53 | + 'jpg', | |
54 | + 'gif', | |
55 | + 'png', | |
56 | + ], | |
57 | + 'initialPreview' => !empty( $model->imageUrl ) ? \common\components\artboximage\ArtboxImageHelper::getImage( | |
58 | + $model->imageUrl, | |
59 | + 'list' | |
60 | + ) : '', | |
61 | + 'overwriteInitial' => true, | |
62 | + 'showRemove' => false, | |
63 | + 'showUpload' => false, | |
64 | + 'previewFileType' => 'image', | |
65 | + ], | |
66 | + ] | |
67 | + ) | |
68 | + ->hint( | |
69 | + ( ( $model->tax_group_id == 5 ) ? 'Для корректного отображения на сайте, размер изображения должен быть 262x144 либо соблюдать соотношение сторон примерно 2:1' : '' ) | |
70 | + ); ?> | |
71 | + <?= $form->field($model, 'sort') | |
72 | + ->textInput() ?> | |
73 | + | |
74 | + <?php | |
75 | + echo LanguageForm::widget( | |
76 | + [ | |
77 | + 'modelLangs' => $modelLangs, | |
78 | + 'formView' => '@common/modules/rubrication/views/tax-option/_form_language', | |
79 | + 'form' => $form, | |
80 | + ] | |
81 | + ); | |
82 | + ?> | |
83 | + | |
84 | + <div class="form-group"> | |
85 | + <?= Html::submitButton( | |
86 | + $model->isNewRecord ? Yii::t('rubrication', 'Create') : Yii::t('rubrication', 'Update'), | |
87 | + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ] | |
88 | + ) ?> | |
89 | + <?php if ($model->isNewRecord) : ?> | |
90 | + <?= Html::submitButton( | |
91 | + Yii::t('rubrication', 'Create and continue'), | |
92 | + [ | |
93 | + 'name' => 'create_and_new', | |
94 | + 'class' => 'btn btn-primary', | |
95 | + ] | |
96 | + ) ?> | |
97 | + <?php endif ?> | |
98 | + </div> | |
99 | + | |
100 | + <?php ActiveForm::end(); ?> | |
101 | + | |
102 | +</div> | ... | ... |
artbox-ecommerce/views/tax-option/_form_language.php
0 → 100755
1 | +++ a/artbox-ecommerce/views/tax-option/_form_language.php | |
1 | +<?php | |
2 | + use common\modules\language\models\Language; | |
3 | + use artweb\artbox\ecommerce\models\TaxOptionLang; | |
4 | + use yii\web\View; | |
5 | + use yii\widgets\ActiveForm; | |
6 | + | |
7 | + /** | |
8 | + * @var TaxOptionLang $model_lang | |
9 | + * @var Language $language | |
10 | + * @var ActiveForm $form | |
11 | + * @var View $this | |
12 | + */ | |
13 | +?> | |
14 | +<?= $form->field($model_lang, '[' . $language->id . ']value') | |
15 | + ->textInput([ 'maxlength' => true ]); ?> | |
16 | +<?= $form->field($model_lang, '[' . $language->id . ']alias') | |
17 | + ->textInput([ 'maxlength' => true ]); ?> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-option/create.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxOptionLang; | |
5 | + use yii\helpers\Html; | |
6 | + | |
7 | + /** | |
8 | + * @var yii\web\View $this | |
9 | + * @var artweb\artbox\ecommerce\models\TaxOption $model | |
10 | + * @var TaxGroup $group | |
11 | + * @var TaxOptionLang[] $modelLangs | |
12 | + */ | |
13 | + $this->title = Yii::t('rubrication', 'Create Tax Option'); | |
14 | + $this->params[ 'breadcrumbs' ][] = [ | |
15 | + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'), | |
16 | + 'url' => [ | |
17 | + 'tax-group/index', | |
18 | + 'level' => $group->level, | |
19 | + ], | |
20 | + ]; | |
21 | + $this->params[ 'breadcrumbs' ][] = [ | |
22 | + 'label' => $group->lang->title, | |
23 | + 'url' => [ | |
24 | + 'tax-group/update', | |
25 | + 'id' => $group->id, | |
26 | + 'level' => $group->level, | |
27 | + ], | |
28 | + ]; | |
29 | + $this->params[ 'breadcrumbs' ][] = [ | |
30 | + 'label' => Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]), | |
31 | + 'url' => [ | |
32 | + 'index', | |
33 | + 'group' => $group->id, | |
34 | + 'level' => $group->level, | |
35 | + ], | |
36 | + ]; | |
37 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
38 | +?> | |
39 | +<div class="tax-option-create"> | |
40 | + | |
41 | + <h1><?= Html::encode($this->title) ?></h1> | |
42 | + | |
43 | + <?= $this->render('_form', [ | |
44 | + 'model' => $model, | |
45 | + 'modelLangs' => $modelLangs, | |
46 | + 'group' => $group, | |
47 | + ]) ?> | |
48 | + | |
49 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-option/index.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxOption; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\grid\GridView; | |
7 | + | |
8 | + /** | |
9 | + * @var yii\web\View $this | |
10 | + * @var artweb\artbox\ecommerce\models\TaxOptionSearch $searchModel | |
11 | + * @var yii\data\ActiveDataProvider $dataProvider | |
12 | + * @var TaxGroup $group | |
13 | + */ | |
14 | + | |
15 | + $this->title = Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]); | |
16 | + $this->params[ 'breadcrumbs' ][] = [ | |
17 | + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t( | |
18 | + 'rubrication', | |
19 | + 'Product Groups' | |
20 | + ), | |
21 | + 'url' => [ | |
22 | + 'tax-group/index', | |
23 | + 'level' => $group->level, | |
24 | + ], | |
25 | + ]; | |
26 | + $this->params[ 'breadcrumbs' ][] = [ | |
27 | + 'label' => $group->lang->title, | |
28 | + 'url' => [ | |
29 | + 'tax-group/update', | |
30 | + 'id' => $group->id, | |
31 | + 'level' => $group->level, | |
32 | + ], | |
33 | + ]; | |
34 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
35 | +?> | |
36 | +<div class="tax-option-index"> | |
37 | + | |
38 | + <h1><?= Html::encode($this->title) ?></h1> | |
39 | + | |
40 | + <p> | |
41 | + <?= Html::a( | |
42 | + Yii::t('rubrication', 'Create Option'), | |
43 | + [ 'create?group=' . $group->id ], | |
44 | + [ 'class' => 'btn btn-success' ] | |
45 | + ) ?> | |
46 | + </p> | |
47 | + | |
48 | + <?php echo GridView::widget( | |
49 | + [ | |
50 | + 'dataProvider' => $dataProvider, | |
51 | + 'filterModel' => $searchModel, | |
52 | + 'columns' => [ | |
53 | + [ 'class' => 'yii\grid\SerialColumn' ], | |
54 | + 'id', | |
55 | + [ | |
56 | + 'attribute' => 'value', | |
57 | + 'value' => 'lang.value', | |
58 | + ], | |
59 | + 'imageUrl:image', | |
60 | + [ | |
61 | + 'label' => $group->level ? \Yii::t('rubrication', 'Variants count') : \Yii::t( | |
62 | + 'rubrication', | |
63 | + 'Products count' | |
64 | + ), | |
65 | + 'value' => function ($model) use ($group) { | |
66 | + /** | |
67 | + * @var TaxOption $model | |
68 | + */ | |
69 | + return count($group->level ? $model->productVariants : $model->products); | |
70 | + }, | |
71 | + ], | |
72 | + [ | |
73 | + 'class' => 'yii\grid\ActionColumn', | |
74 | + 'template' => '{update} {delete}', | |
75 | + ], | |
76 | + ], | |
77 | + ] | |
78 | + ); ?> | |
79 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-option/update.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxOptionLang; | |
5 | + use yii\helpers\Html; | |
6 | + | |
7 | + /** | |
8 | + * @var yii\web\View $this | |
9 | + * @var artweb\artbox\ecommerce\models\TaxOption $model | |
10 | + * @var TaxGroup $group | |
11 | + * @var TaxOptionLang[] $modelLangs | |
12 | + */ | |
13 | + $this->title = Yii::t('rubrication', 'Update {modelClass}: ', [ | |
14 | + 'modelClass' => 'Tax Option', | |
15 | + ]) . ' ' . $model->lang->value; | |
16 | + $this->params[ 'breadcrumbs' ][] = [ | |
17 | + 'label' => $group->level ? Yii::t('rubrication', 'Modification Groups') : Yii::t('rubrication', 'Product Groups'), | |
18 | + 'url' => [ | |
19 | + 'tax-group/index', | |
20 | + 'level' => $group->level, | |
21 | + ], | |
22 | + ]; | |
23 | + $this->params[ 'breadcrumbs' ][] = [ | |
24 | + 'label' => $group->lang->title, | |
25 | + 'url' => [ | |
26 | + 'tax-group/update', | |
27 | + 'id' => $group->id, | |
28 | + 'level' => $group->level, | |
29 | + ], | |
30 | + ]; | |
31 | + $this->params[ 'breadcrumbs' ][] = [ | |
32 | + 'label' => Yii::t('rubrication', 'Options for group {group}', [ 'group' => $group->lang->title ]), | |
33 | + 'url' => [ | |
34 | + 'index', | |
35 | + 'group' => $group->id, | |
36 | + 'level' => $group->level, | |
37 | + ], | |
38 | + ]; | |
39 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
40 | +?> | |
41 | +<div class="tax-option-update"> | |
42 | + | |
43 | + <h1><?= Html::encode($this->title) ?></h1> | |
44 | + | |
45 | + <?= $this->render('_form', [ | |
46 | + 'model' => $model, | |
47 | + 'modelLangs' => $modelLangs, | |
48 | + 'group' => $group, | |
49 | + ]) ?> | |
50 | + | |
51 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/tax-option/view.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
4 | + use artweb\artbox\ecommerce\models\TaxOption; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + use yii\widgets\DetailView; | |
8 | + | |
9 | + /** | |
10 | + * @var View $this | |
11 | + * @var TaxOption $model | |
12 | + * @var TaxGroup $group | |
13 | + */ | |
14 | + | |
15 | + $this->title = $model->id; | |
16 | + $this->params[ 'breadcrumbs' ][] = [ | |
17 | + 'label' => Yii::t('rubrication', 'Groups'), | |
18 | + 'url' => [ 'tax-group/index' ], | |
19 | + ]; | |
20 | + $this->params[ 'breadcrumbs' ][] = [ | |
21 | + 'label' => Yii::t('rubrication', $group->id), | |
22 | + 'url' => [ | |
23 | + 'index', | |
24 | + 'group' => $group->id, | |
25 | + ], | |
26 | + ]; | |
27 | + $this->params[ 'breadcrumbs' ][] = [ | |
28 | + 'label' => Yii::t('rubrication', Yii::t('rubrication', 'Options of {title}', [ 'title' => $group->id ])), | |
29 | + 'url' => [ | |
30 | + 'index', | |
31 | + 'group' => $group->id, | |
32 | + ], | |
33 | + ]; | |
34 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
35 | +?> | |
36 | +<div class="tax-option-view"> | |
37 | + | |
38 | + <h1><?= Html::encode($this->title) ?></h1> | |
39 | + | |
40 | + <p> | |
41 | + <?= Html::a( | |
42 | + Yii::t('rubrication', 'Update'), | |
43 | + [ | |
44 | + 'update', | |
45 | + 'id' => $model->id, | |
46 | + ], | |
47 | + [ 'class' => 'btn btn-primary' ] | |
48 | + ) ?> | |
49 | + <?= Html::a( | |
50 | + Yii::t('rubrication', 'Delete'), | |
51 | + [ | |
52 | + 'delete', | |
53 | + 'id' => $model->id, | |
54 | + ], | |
55 | + [ | |
56 | + 'class' => 'btn btn-danger', | |
57 | + 'data' => [ | |
58 | + 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'), | |
59 | + 'method' => 'post', | |
60 | + ], | |
61 | + ] | |
62 | + ) ?> | |
63 | + <?= Html::a( | |
64 | + Yii::t('rubrication', 'Create Option'), | |
65 | + [ 'tax-option/create?group=' . $model->id ], | |
66 | + [ 'class' => 'btn btn-success' ] | |
67 | + ) ?> | |
68 | + </p> | |
69 | + | |
70 | + <?= DetailView::widget( | |
71 | + [ | |
72 | + 'model' => $model, | |
73 | + 'attributes' => [ | |
74 | + 'id', | |
75 | + 'group.id', | |
76 | + 'sort', | |
77 | + ], | |
78 | + ] | |
79 | + ) ?> | |
80 | + | |
81 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/_form.php | |
1 | +<?php | |
2 | + | |
3 | + use common\modules\language\widgets\LanguageForm; | |
4 | + use artweb\artbox\ecommerce\models\Product; | |
5 | + use artweb\artbox\ecommerce\models\ProductStock; | |
6 | + use artweb\artbox\ecommerce\models\ProductUnit; | |
7 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
8 | + use artweb\artbox\ecommerce\models\ProductVariantLang; | |
9 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
10 | + use yii\db\ActiveQuery; | |
11 | + use yii\helpers\Html; | |
12 | + use yii\web\View; | |
13 | + use yii\widgets\ActiveForm; | |
14 | + use yii\helpers\ArrayHelper; | |
15 | + use wbraganca\dynamicform\DynamicFormWidget; | |
16 | + | |
17 | + /** | |
18 | + * @var View $this | |
19 | + * @var ProductVariant $model | |
20 | + * @var ProductVariantLang[] $modelLangs | |
21 | + * @var ActiveQuery $groups | |
22 | + * @var ProductStock[] $stocks | |
23 | + * @var ActiveForm $form | |
24 | + * @var Product $product | |
25 | + */ | |
26 | + | |
27 | + $js = ' | |
28 | +$(".dynamicform_wrapper").on("beforeDelete", function(e, item) { | |
29 | + if (! confirm("Are you sure you want to delete this item?")) { | |
30 | + return false; | |
31 | + } | |
32 | + return true; | |
33 | +}); | |
34 | + | |
35 | +$(".dynamicform_wrapper").on("limitReached", function(e, item) { | |
36 | + alert("Limit reached"); | |
37 | +}); | |
38 | +'; | |
39 | + | |
40 | + $this->registerJs($js, View::POS_END); | |
41 | +?> | |
42 | +<div class="product-form"> | |
43 | + | |
44 | + <?php $form = ActiveForm::begin( | |
45 | + [ | |
46 | + 'id' => 'dynamic-form', | |
47 | + 'options' => [ 'enctype' => 'multipart/form-data' ], | |
48 | + ] | |
49 | + ); ?> | |
50 | + | |
51 | + <?= $form->field($model, 'product_id') | |
52 | + ->hiddenInput() | |
53 | + ->label(false); ?> | |
54 | + | |
55 | + <?= $form->field($model, 'sku') | |
56 | + ->textarea(); ?> | |
57 | + <?= $form->field($model, 'price') | |
58 | + ->textarea(); ?> | |
59 | + <?= $form->field($model, 'price_old') | |
60 | + ->textarea(); ?> | |
61 | + <?= $form->field($model, 'imagesUpload[]') | |
62 | + ->widget( | |
63 | + \kartik\file\FileInput::className(), | |
64 | + [ | |
65 | + 'language' => 'ru', | |
66 | + 'options' => [ | |
67 | + 'accept' => 'image/*', | |
68 | + 'multiple' => true, | |
69 | + ], | |
70 | + 'pluginOptions' => [ | |
71 | + 'allowedFileExtensions' => [ | |
72 | + 'jpg', | |
73 | + 'gif', | |
74 | + 'png', | |
75 | + ], | |
76 | + 'initialPreview' => !empty( $model->imagesHTML ) ? $model->imagesHTML : [], | |
77 | + 'initialPreviewConfig' => $model->imagesConfig, | |
78 | + 'overwriteInitial' => false, | |
79 | + 'showRemove' => false, | |
80 | + 'showUpload' => false, | |
81 | + 'uploadAsync' => !empty( $model->id ), | |
82 | + 'previewFileType' => 'image', | |
83 | + ], | |
84 | + ] | |
85 | + ); ?> | |
86 | + | |
87 | + <?= LanguageForm::widget( | |
88 | + [ | |
89 | + 'modelLangs' => $modelLangs, | |
90 | + 'formView' => '@common/modules/product/views/variant/_form_language', | |
91 | + 'form' => $form, | |
92 | + ] | |
93 | + ) ?> | |
94 | + | |
95 | + <?php DynamicFormWidget::begin( | |
96 | + [ | |
97 | + 'widgetContainer' => 'dynamicform_wrapper', | |
98 | + // required: only alphanumeric characters plus "_" [A-Za-z0-9_] | |
99 | + 'widgetBody' => '.container-items', | |
100 | + // required: css class selector | |
101 | + 'widgetItem' => '.item', | |
102 | + // required: css class | |
103 | + 'limit' => 10, | |
104 | + // the maximum times, an element can be added (default 999) | |
105 | + 'min' => 0, | |
106 | + // 0 or 1 (default 1) | |
107 | + 'insertButton' => '.add-item', | |
108 | + // css class | |
109 | + 'deleteButton' => '.remove-item', | |
110 | + // css class | |
111 | + 'model' => $stocks[ 0 ], | |
112 | + 'formId' => 'dynamic-form', | |
113 | + 'formFields' => [ | |
114 | + 'quantity', | |
115 | + 'title', | |
116 | + ], | |
117 | + ] | |
118 | + ); ?> | |
119 | + | |
120 | + <div class="panel panel-default"> | |
121 | + <div class="panel-heading"> | |
122 | + <h4> | |
123 | + <i class="glyphicon glyphicon-envelope"></i> Склады | |
124 | + <button type="button" class="add-item btn btn-success btn-sm pull-right"> | |
125 | + <i class="glyphicon glyphicon-plus"></i> Add | |
126 | + </button> | |
127 | + </h4> | |
128 | + </div> | |
129 | + <div class="panel-body"> | |
130 | + <div class="container-items"><!-- widgetBody --> | |
131 | + <?php foreach ($stocks as $i => $stock): ?> | |
132 | + <div class="item panel panel-default"><!-- widgetItem --> | |
133 | + <div class="panel-body"> | |
134 | + <?php | |
135 | + // necessary for update action. | |
136 | + if (!$stock->isNewRecord) { | |
137 | + echo Html::activeHiddenInput($stock, "[{$i}]stock_id"); | |
138 | + } | |
139 | + ?> | |
140 | + <div class="row"> | |
141 | + <div class="col-sm-5"> | |
142 | + <?= $form->field($stock, "[{$i}]quantity") | |
143 | + ->textInput([ 'maxlength' => true ]) ?> | |
144 | + </div> | |
145 | + <div class="col-sm-5"> | |
146 | + <?= $form->field($stock, "[{$i}]title") | |
147 | + ->textInput([ 'maxlength' => true ]) ?> | |
148 | + </div> | |
149 | + <div class="col-sm-2" style="margin-top: 30px"> | |
150 | + <button type="button" class="remove-item btn btn-danger btn-xs"> | |
151 | + <i class="glyphicon glyphicon-minus"></i></button> | |
152 | + </div> | |
153 | + </div><!-- .row --> | |
154 | + </div> | |
155 | + </div> | |
156 | + <?php endforeach; ?> | |
157 | + </div> | |
158 | + </div> | |
159 | + </div><!-- .panel --> | |
160 | + <?php DynamicFormWidget::end(); ?> | |
161 | + | |
162 | + <?= $form->field($model, 'product_unit_id') | |
163 | + ->dropDownList( | |
164 | + ArrayHelper::map( | |
165 | + ProductUnit::find() | |
166 | + ->with('lang') | |
167 | + ->all(), | |
168 | + 'id', | |
169 | + 'lang.title' | |
170 | + ) | |
171 | + ) | |
172 | + ->label(Yii::t('product', 'Unit')) ?> | |
173 | + | |
174 | + <?php if (!empty( $groups )) { | |
175 | + foreach ($groups->with('lang') | |
176 | + ->all() as $group) { | |
177 | + /** | |
178 | + * @var TaxGroup $group | |
179 | + */ | |
180 | + echo $form->field($model, 'options') | |
181 | + ->checkboxList( | |
182 | + ArrayHelper::map( | |
183 | + $group->getOptions() | |
184 | + ->with('lang') | |
185 | + ->all(), | |
186 | + 'id', | |
187 | + 'lang.value' | |
188 | + ), | |
189 | + [ | |
190 | + 'multiple' => true, | |
191 | + 'unselect' => null, | |
192 | + ] | |
193 | + ) | |
194 | + ->label($group->lang->title); | |
195 | + } | |
196 | + } ?> | |
197 | + | |
198 | + <div class="form-group"> | |
199 | + <?= Html::submitButton( | |
200 | + $model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), | |
201 | + [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ] | |
202 | + ) ?> | |
203 | + </div> | |
204 | + | |
205 | + <?php ActiveForm::end(); ?> | |
206 | + | |
207 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/_form_language.php | |
1 | +<?php | |
2 | + use common\modules\language\models\Language; | |
3 | + use artweb\artbox\ecommerce\models\ProductVariantLang; | |
4 | + use yii\web\View; | |
5 | + use yii\widgets\ActiveForm; | |
6 | + | |
7 | + /** | |
8 | + * @var ProductVariantLang $model_lang | |
9 | + * @var Language $language | |
10 | + * @var ActiveForm $form | |
11 | + * @var View $this | |
12 | + */ | |
13 | +?> | |
14 | +<?= $form->field($model_lang, '[' . $language->id . ']title') | |
15 | + ->textInput([ 'maxlength' => true ]); ?> | |
0 | 16 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/create.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Product; | |
4 | + use artweb\artbox\ecommerce\models\ProductStock; | |
5 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
6 | + use artweb\artbox\ecommerce\models\ProductVariantLang; | |
7 | + use yii\db\ActiveQuery; | |
8 | + use yii\helpers\Html; | |
9 | + use yii\web\View; | |
10 | + | |
11 | + /** | |
12 | + * @var View $this | |
13 | + * @var ProductVariant $model | |
14 | + * @var ProductVariantLang[] $modelLangs | |
15 | + * @var ActiveQuery $groups | |
16 | + * @var ProductStock[] $stocks | |
17 | + * @var Product $product | |
18 | + */ | |
19 | + $this->title = Yii::t('product', 'Create Variant'); | |
20 | + $this->params[ 'breadcrumbs' ][] = [ | |
21 | + 'label' => Yii::t('product', 'Products'), | |
22 | + 'url' => [ '/product/manage/index' ], | |
23 | + ]; | |
24 | + $this->params[ 'breadcrumbs' ][] = [ | |
25 | + 'label' => $product->lang->title, | |
26 | + 'url' => [ | |
27 | + '/product/manage/view', | |
28 | + 'id' => $product->id, | |
29 | + ], | |
30 | + ]; | |
31 | + $this->params[ 'breadcrumbs' ][] = [ | |
32 | + 'label' => Yii::t('product', 'Variants'), | |
33 | + 'url' => [ | |
34 | + 'index', | |
35 | + 'product_id' => $product->id, | |
36 | + ], | |
37 | + ]; | |
38 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
39 | +?> | |
40 | +<div class="product-create"> | |
41 | + | |
42 | + <h1><?= Html::encode($this->title) ?></h1> | |
43 | + | |
44 | + <?= $this->render( | |
45 | + '_form', | |
46 | + [ | |
47 | + 'model' => $model, | |
48 | + 'modelLangs' => $modelLangs, | |
49 | + 'groups' => $groups, | |
50 | + 'stocks' => $stocks, | |
51 | + 'product' => $product, | |
52 | + ] | |
53 | + ) ?> | |
54 | + | |
55 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/index.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Product; | |
4 | + use artweb\artbox\ecommerce\models\ProductVariantSearch; | |
5 | + use yii\data\ActiveDataProvider; | |
6 | + use yii\helpers\Html; | |
7 | + use yii\grid\GridView; | |
8 | + use yii\helpers\Url; | |
9 | + use yii\web\View; | |
10 | + | |
11 | + /** | |
12 | + * @var View $this | |
13 | + * @var ProductVariantSearch $searchModel | |
14 | + * @var ActiveDataProvider $dataProvider | |
15 | + * @var Product $product | |
16 | + */ | |
17 | + | |
18 | + $this->title = Yii::t('product', 'Variants for ') . $product->lang->title; | |
19 | + $this->params[ 'breadcrumbs' ][] = [ | |
20 | + 'label' => Yii::t('product', 'Products'), | |
21 | + 'url' => [ '/product/manage/index' ], | |
22 | + ]; | |
23 | + $this->params[ 'breadcrumbs' ][] = [ | |
24 | + 'label' => $product->lang->title, | |
25 | + 'url' => [ | |
26 | + '/product/manage/view', | |
27 | + 'id' => $product->id, | |
28 | + ], | |
29 | + ]; | |
30 | + $this->params[ 'breadcrumbs' ][] = \Yii::t('product', 'Variants'); | |
31 | +?> | |
32 | +<div class="product-index"> | |
33 | + | |
34 | + <h1><?= Html::encode($this->title) ?></h1> | |
35 | + | |
36 | + <p> | |
37 | + <?= Html::a( | |
38 | + Yii::t('product', 'Create Variant'), | |
39 | + Url::toRoute( | |
40 | + [ | |
41 | + 'create', | |
42 | + 'product_id' => $product->id, | |
43 | + ] | |
44 | + ), | |
45 | + [ 'class' => 'btn btn-success' ] | |
46 | + ) ?> | |
47 | + </p> | |
48 | + <?= GridView::widget( | |
49 | + [ | |
50 | + 'dataProvider' => $dataProvider, | |
51 | + 'filterModel' => $searchModel, | |
52 | + 'columns' => [ | |
53 | + 'id', | |
54 | + [ | |
55 | + 'attribute' => 'variantName', | |
56 | + 'value' => 'lang.title', | |
57 | + ], | |
58 | + 'sku', | |
59 | + 'price', | |
60 | + 'price_old', | |
61 | + 'stock', | |
62 | + 'image.imageUrl:image', | |
63 | + [ | |
64 | + 'class' => 'yii\grid\ActionColumn', | |
65 | + 'buttons' => [ | |
66 | + 'view' => function ($url, $model) { | |
67 | + return Html::a( | |
68 | + '<span class="glyphicon glyphicon-eye-open"></span>', | |
69 | + Url::to( | |
70 | + [ | |
71 | + 'view', | |
72 | + 'product_id' => $model->product_id, | |
73 | + 'id' => $model->id, | |
74 | + ] | |
75 | + ), | |
76 | + [ | |
77 | + 'title' => \Yii::t('app', "Просмотр"), | |
78 | + ] | |
79 | + ); | |
80 | + }, | |
81 | + 'update' => function ($url, $model) { | |
82 | + return Html::a( | |
83 | + '<span class="glyphicon glyphicon-pencil"></span>', | |
84 | + Url::to( | |
85 | + [ | |
86 | + 'update', | |
87 | + 'product_id' => $model->product_id, | |
88 | + 'id' => $model->id, | |
89 | + ] | |
90 | + ), | |
91 | + [ | |
92 | + 'title' => \Yii::t('app', "Редактировать"), | |
93 | + ] | |
94 | + ); | |
95 | + }, | |
96 | + 'delete' => function ($url, $model) { | |
97 | + | |
98 | + return Html::a( | |
99 | + '<span class="glyphicon glyphicon-trash"></span>', | |
100 | + Url::to( | |
101 | + [ | |
102 | + 'delete', | |
103 | + 'product_id' => $model->product_id, | |
104 | + 'id' => $model->id, | |
105 | + ] | |
106 | + ), | |
107 | + [ | |
108 | + 'title' => Yii::t('yii', 'Delete'), | |
109 | + 'data-confirm' => Yii::t('yii', 'Are you sure to delete this item?'), | |
110 | + 'data-method' => 'post', | |
111 | + ] | |
112 | + ); | |
113 | + | |
114 | + }, | |
115 | + ], | |
116 | + ], | |
117 | + ], | |
118 | + ] | |
119 | + ); ?> | |
120 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/update.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\Product; | |
4 | + use artweb\artbox\ecommerce\models\ProductStock; | |
5 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
6 | + use artweb\artbox\ecommerce\models\ProductVariantLang; | |
7 | + use yii\db\ActiveQuery; | |
8 | + use yii\helpers\Html; | |
9 | + use yii\helpers\Url; | |
10 | + use yii\web\View; | |
11 | + | |
12 | + /** | |
13 | + * @var View $this | |
14 | + * @var ProductVariant $model | |
15 | + * @var ProductVariantLang[] $modelLangs | |
16 | + * @var ActiveQuery $groups | |
17 | + * @var ProductStock[] $stocks | |
18 | + * @var Product $product | |
19 | + */ | |
20 | + $this->title = Yii::t( | |
21 | + 'product', | |
22 | + 'Update {modelClass}: ', | |
23 | + [ | |
24 | + 'modelClass' => 'Product', | |
25 | + ] | |
26 | + ) . ' ' . $model->lang->title; | |
27 | + $this->params[ 'breadcrumbs' ][] = [ | |
28 | + 'label' => Yii::t('product', 'Products'), | |
29 | + 'url' => [ '/product/manage/index' ], | |
30 | + ]; | |
31 | + $this->params[ 'breadcrumbs' ][] = [ | |
32 | + 'label' => $model->product->lang->title, | |
33 | + 'url' => [ | |
34 | + '/product/manage/view', | |
35 | + 'id' => $model->product->id, | |
36 | + ], | |
37 | + ]; | |
38 | + $this->params[ 'breadcrumbs' ][] = [ | |
39 | + 'label' => Yii::t('product', 'Variants'), | |
40 | + 'url' => Url::to( | |
41 | + [ | |
42 | + 'index', | |
43 | + 'product_id' => $model->product->id, | |
44 | + ] | |
45 | + ), | |
46 | + ]; | |
47 | + $this->params[ 'breadcrumbs' ][] = [ | |
48 | + 'label' => Yii::t('product', $model->lang->title), | |
49 | + 'url' => Url::to( | |
50 | + [ | |
51 | + 'view', | |
52 | + 'id' => $model->id, | |
53 | + ] | |
54 | + ), | |
55 | + ]; | |
56 | + $this->params[ 'breadcrumbs' ][] = Yii::t('product', 'Update'); | |
57 | +?> | |
58 | +<div class="product-update"> | |
59 | + | |
60 | + <h1><?= Html::encode($this->title) ?></h1> | |
61 | + | |
62 | + <?= $this->render( | |
63 | + '_form', | |
64 | + [ | |
65 | + 'model' => $model, | |
66 | + 'modelLangs' => $modelLangs, | |
67 | + 'groups' => $groups, | |
68 | + 'stocks' => $stocks, | |
69 | + 'product' => $product, | |
70 | + ] | |
71 | + ) ?> | |
72 | + | |
73 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/views/variant/view.php | |
1 | +<?php | |
2 | + | |
3 | + use artweb\artbox\ecommerce\models\ProductVariant; | |
4 | + use artweb\artbox\ecommerce\models\TaxGroup; | |
5 | + use yii\helpers\Html; | |
6 | + use yii\web\View; | |
7 | + use yii\widgets\DetailView; | |
8 | + | |
9 | + /** | |
10 | + * @var View $this | |
11 | + * @var ProductVariant $model | |
12 | + * @var TaxGroup[] $properties | |
13 | + */ | |
14 | + | |
15 | + $this->title = $model->lang->title; | |
16 | + $this->params[ 'breadcrumbs' ][] = [ | |
17 | + 'label' => Yii::t('product', 'Products'), | |
18 | + 'url' => [ 'index' ], | |
19 | + ]; | |
20 | + $this->params[ 'breadcrumbs' ][] = [ | |
21 | + 'label' => $model->product->lang->title, | |
22 | + 'url' => [ | |
23 | + 'view', | |
24 | + 'id' => $model->product->id, | |
25 | + ], | |
26 | + ]; | |
27 | + $this->params[ 'breadcrumbs' ][] = [ | |
28 | + 'label' => Yii::t('product', 'Variants'), | |
29 | + 'url' => [ '/product/variant?product_id=' . $model->product->id ], | |
30 | + ]; | |
31 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
32 | + $properties_string = ''; | |
33 | + foreach ($properties as $property) { | |
34 | + $options_string = ''; | |
35 | + foreach ($property->options as $option) { | |
36 | + $options_string .= Html::tag('li', $option->lang->value); | |
37 | + } | |
38 | + $properties_string .= Html::tag('p', $property->lang->title) . Html::tag('ul', $options_string); | |
39 | + } | |
40 | +?> | |
41 | +<div class="product-view"> | |
42 | + | |
43 | + <h1><?= Html::encode($this->title) ?></h1> | |
44 | + | |
45 | + <p> | |
46 | + <?= Html::a( | |
47 | + Yii::t('product', 'Update'), | |
48 | + [ | |
49 | + 'update', | |
50 | + 'id' => $model->id, | |
51 | + ], | |
52 | + [ 'class' => 'btn btn-primary' ] | |
53 | + ) ?> | |
54 | + <?= Html::a( | |
55 | + Yii::t('product', 'Delete'), | |
56 | + [ | |
57 | + 'delete', | |
58 | + 'id' => $model->id, | |
59 | + ], | |
60 | + [ | |
61 | + 'class' => 'btn btn-danger', | |
62 | + 'data' => [ | |
63 | + 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'), | |
64 | + 'method' => 'post', | |
65 | + ], | |
66 | + ] | |
67 | + ) ?> | |
68 | + </p> | |
69 | + | |
70 | + <?= DetailView::widget( | |
71 | + [ | |
72 | + 'model' => $model, | |
73 | + 'attributes' => [ | |
74 | + 'id', | |
75 | + 'lang.title', | |
76 | + 'sku', | |
77 | + 'price', | |
78 | + 'price_old', | |
79 | + 'stock', | |
80 | + 'productUnit.lang.title', | |
81 | + [ | |
82 | + 'attribute' => 'product_id', | |
83 | + 'value' => Html::a( | |
84 | + $model->product->fullname, | |
85 | + [ | |
86 | + '/product/manage/view', | |
87 | + 'id' => $model->id, | |
88 | + ] | |
89 | + ), | |
90 | + 'format' => 'html', | |
91 | + ], | |
92 | + 'image.imageUrl:image', | |
93 | + [ | |
94 | + 'label' => \Yii::t('app', 'Properties'), | |
95 | + 'value' => $properties_string, | |
96 | + 'format' => 'html', | |
97 | + ], | |
98 | + ], | |
99 | + ] | |
100 | + ) ?> | |
101 | + | |
102 | +</div> | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/brandsCarouselWidget.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\widgets; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\models\Brand; | |
6 | + use yii\base\Widget; | |
7 | + | |
8 | + class brandsCarouselWidget extends Widget | |
9 | + { | |
10 | + | |
11 | + public function init() | |
12 | + { | |
13 | + parent::init(); | |
14 | + } | |
15 | + | |
16 | + public function run() | |
17 | + { | |
18 | + $brands = Brand::find() | |
19 | + ->with('lang') | |
20 | + ->all(); | |
21 | + return $this->render( | |
22 | + 'brandsCarousel', | |
23 | + [ | |
24 | + 'brands' => $brands, | |
25 | + ] | |
26 | + ); | |
27 | + } | |
28 | + } | |
29 | + | |
0 | 30 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/lastProducts.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\widgets; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
6 | + use yii\base\Widget; | |
7 | + | |
8 | + class lastProducts extends Widget | |
9 | + { | |
10 | + | |
11 | + public function init() | |
12 | + { | |
13 | + parent::init(); | |
14 | + } | |
15 | + | |
16 | + public function run() | |
17 | + { | |
18 | + return $this->render( | |
19 | + 'products_block', | |
20 | + [ | |
21 | + 'title' => \Yii::t('product', 'Вы недавно просматривали'), | |
22 | + 'class' => 'last-products', | |
23 | + 'products' => ProductHelper::getLastProducts(true), | |
24 | + ] | |
25 | + ); | |
26 | + } | |
27 | + } | |
28 | + | |
0 | 29 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/similarProducts.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\widgets; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
6 | + use yii\base\Widget; | |
7 | + use Yii; | |
8 | + | |
9 | + class similarProducts extends Widget | |
10 | + { | |
11 | + | |
12 | + public $count = 10; | |
13 | + | |
14 | + public $title; | |
15 | + | |
16 | + public $product; | |
17 | + | |
18 | + public function init() | |
19 | + { | |
20 | + parent::init(); | |
21 | + } | |
22 | + | |
23 | + public function run() | |
24 | + { | |
25 | + $products = ProductHelper::getSimilarProducts($this->product, $this->count); | |
26 | + | |
27 | + if (!$this->title) { | |
28 | + $this->title = Yii::t('product', 'Similar products'); | |
29 | + } | |
30 | + | |
31 | + return $this->render( | |
32 | + 'products_block', | |
33 | + [ | |
34 | + 'title' => $this->title, | |
35 | + 'class' => 'similar-products', | |
36 | + 'products' => $products, | |
37 | + ] | |
38 | + ); | |
39 | + } | |
40 | + } | |
41 | + | |
0 | 42 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/specialProducts.php | |
1 | +<?php | |
2 | + | |
3 | + namespace artweb\artbox\ecommerce\widgets; | |
4 | + | |
5 | + use artweb\artbox\ecommerce\helpers\ProductHelper; | |
6 | + use yii\base\Widget; | |
7 | + use Yii; | |
8 | + | |
9 | + class specialProducts extends Widget | |
10 | + { | |
11 | + | |
12 | + public $type = 'top'; | |
13 | + | |
14 | + public $count = 8; | |
15 | + | |
16 | + public $title; | |
17 | + | |
18 | + public function init() | |
19 | + { | |
20 | + parent::init(); | |
21 | + } | |
22 | + | |
23 | + public function run() | |
24 | + { | |
25 | + $products = ProductHelper::getSpecialProducts($this->type, $this->count); | |
26 | + | |
27 | + if (!$this->title) { | |
28 | + switch ($this->type) { | |
29 | + case 'top': | |
30 | + $this->title = Yii::t('product', 'Top products'); | |
31 | + break; | |
32 | + case 'promo': | |
33 | + $this->title = Yii::t('product', 'Promo products'); | |
34 | + break; | |
35 | + case 'new': | |
36 | + $this->title = Yii::t('product', 'New products'); | |
37 | + break; | |
38 | + } | |
39 | + } | |
40 | + | |
41 | + return $this->render( | |
42 | + 'products_block', | |
43 | + [ | |
44 | + 'title' => $this->title, | |
45 | + 'class' => $this->type, | |
46 | + 'products' => $products, | |
47 | + ] | |
48 | + ); | |
49 | + } | |
50 | + } | |
51 | + | |
0 | 52 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/views/brandsCarousel.php | |
1 | +<?php | |
2 | + /** | |
3 | + * @var Brand[] $brands | |
4 | + */ | |
5 | + use common\components\artboximage\ArtboxImageHelper; | |
6 | + use artweb\artbox\ecommerce\models\Brand; | |
7 | + | |
8 | +?> | |
9 | +<div class="slider_prod"> | |
10 | + <div class="pc_prev"></div> | |
11 | + <div class="prods_carousel"> | |
12 | + <ul> | |
13 | + <?php foreach($brands as $brand) { ?> | |
14 | + <li> | |
15 | + <span><a href="<?= \yii\helpers\Url::to('/brands/' . $brand->lang->alias) ?>" title="<?= $brand->lang->title ?>"><?= $brand->image ? ArtboxImageHelper::getImage($brand->imageFile, 'brandlist') : '' ?></a></span> | |
16 | + </li> | |
17 | + <?php } ?> | |
18 | + </ul> | |
19 | + </div> | |
20 | + <div class="pc_next"></div> | |
21 | +</div> | |
0 | 22 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/views/product_smart.php | |
1 | +<?php | |
2 | + /** | |
3 | + * @var $product artweb\artbox\ecommerce\models\Product | |
4 | + */ | |
5 | + use yii\helpers\Html; | |
6 | + use yii\helpers\Url; | |
7 | + | |
8 | +?> | |
9 | +<div class="catalog_item"> | |
10 | + <div class="wrapper"> | |
11 | + <div class="item_container"> | |
12 | + <input class="prodInfo" type="hidden" value="[]"> | |
13 | + <div class="title"> | |
14 | + <?= Html::a( | |
15 | + $product->lang->title, | |
16 | + Url::to( | |
17 | + [ | |
18 | + 'catalog/product', | |
19 | + 'product' => $product->lang->alias, | |
20 | + ] | |
21 | + ), | |
22 | + [ 'class' => 'btn-product-details' ] | |
23 | + ) ?> | |
24 | + </div> | |
25 | + <div class="img"> | |
26 | + <a class="btn-product-details" href="<?= Url::to( | |
27 | + [ | |
28 | + 'catalog/product', | |
29 | + 'product' => $product->lang->alias, | |
30 | + ] | |
31 | + ) ?>"> | |
32 | + <?= \common\components\artboximage\ArtboxImageHelper::getImage( | |
33 | + $product->enabledVariants[ 0 ]->imageUrl, | |
34 | + 'list', | |
35 | + [ | |
36 | + 'alt' => $product->category->lang->title . ' ' . $product->fullname, | |
37 | + 'title' => $product->category->lang->title . ' ' . $product->fullname, | |
38 | + 'class' => 'selected', | |
39 | + ] | |
40 | + ) ?> | |
41 | + </a> | |
42 | + <div class="info_icons"> | |
43 | + <a href="#" class="btn buy_button" data-toggle="modal" data-target="#buyForm" data-id="<?= $product->variant->id; ?>" lang="145">Купить</a> | |
44 | + <ul class="ul wishlike_block hidden"> | |
45 | + <li class="compare hidden"> | |
46 | + <a onclick="add2compare(); return false;" class="compare compare_text_link_3631483" href="#">К сравнению</a> | |
47 | + <span class="icon"></span> | |
48 | + </li> | |
49 | + <li class="like hidden"> | |
50 | + <a class="like like_text_link_3631483" href="#">В избранное</a><span class="icon"></span> | |
51 | + </li> | |
52 | + </ul> | |
53 | + </div> | |
54 | + </div> | |
55 | + <div class="price"> | |
56 | + <div class="dlexfduinxipi"> | |
57 | + Цена: | |
58 | + <span class="main"> | |
59 | + <?= $product->variant->price ?> | |
60 | + <span class="currency">грн</span> | |
61 | + </span> | |
62 | + </div> | |
63 | + </div> | |
64 | + <div class="additional_info params"> | |
65 | + <div class="block_title">Особенности</div> | |
66 | + <div class="descr"> | |
67 | + <div class="info"> | |
68 | + <ul class="sv"> | |
69 | + | |
70 | + <li><span>Бренд:</span> <?= $product->brand->lang->title ?></li> | |
71 | + | |
72 | + <?php foreach ($product->getProperties() as $group): ?> | |
73 | + <li> | |
74 | + <span><?= $group->lang->title ?> <?php foreach ( $group->customOptions as $option ) : ?> </span><?= $option->lang->value ?><?php endforeach ?> | |
75 | + </li> | |
76 | + <?php endforeach; ?> | |
77 | + | |
78 | + | |
79 | + </ul> | |
80 | + </div> | |
81 | + <div class="clearfix"></div> | |
82 | + </div> | |
83 | + <div class="price" style="display: none;"> | |
84 | + <div class="dlexfduinxipi"> | |
85 | + Цена: | |
86 | + <span class="main"> | |
87 | + <?php | |
88 | + | |
89 | + echo '<div class="cost-block" itemprop="offers" itemscope itemtype="http://schema.org/Offer">'; | |
90 | + | |
91 | + // есть скидка | |
92 | + echo '<p class="cost">'; | |
93 | + if ($product->enabledVariants[ 0 ]->price_old != 0 && $product->enabledVariants[ 0 ]->price_old != $product->enabledVariants[ 0 ]->price) { | |
94 | + echo '<strike><span id=\'old_cost\' itemprop="price">' . $product->enabledVariants[ 0 ]->price_old . '</span> грн.</strike> '; | |
95 | + echo $product->enabledVariants[ 0 ]->price . ' <span>грн.</span></p>'; | |
96 | + } else { | |
97 | + echo '<span itemprop="price">' . $product->enabledVariants[ 0 ]->price . ' </span><span>грн.</span></p>'; | |
98 | + } | |
99 | + echo '<meta itemprop="priceCurrency" content = "UAH">'; | |
100 | + echo '</div>'; | |
101 | + | |
102 | + ?> | |
103 | + </span> | |
104 | + </div> | |
105 | + </div> | |
106 | + </div> | |
107 | + <div class="opacity_bg"></div> | |
108 | + </div> | |
109 | + </div> | |
110 | +</div> | |
0 | 111 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/views/products_block.php | |
1 | +<?php | |
2 | + use artweb\artbox\ecommerce\models\Product; | |
3 | + use yii\web\View; | |
4 | + | |
5 | + /** | |
6 | + * @var Product[] $products | |
7 | + */ | |
8 | +?> | |
9 | +<?php if(!empty( $products )) { ?> | |
10 | + <div class="_prd_spec-wr"> | |
11 | + <div class="special-products products<?= ( !empty( $class ) ? ' ' . $class : '' ) ?>"> | |
12 | + <span style="text-align: center; | |
13 | + text-transform: uppercase; | |
14 | + font-size: 20px; display: block; | |
15 | + -webkit-margin-before: 1em; | |
16 | + -webkit-margin-after: 1em; | |
17 | + -webkit-margin-start: 0; | |
18 | + -webkit-margin-end: 0; | |
19 | + font-weight: bold;"><?= $title ?></span> | |
20 | + <div id="<?= $class ?>"> | |
21 | + <?php foreach($products as $product) : ?> | |
22 | + <?= $this->render('product_smart', [ 'product' => $product ]); ?> | |
23 | + <?php endforeach ?> | |
24 | + </div> | |
25 | + <div class="both"></div> | |
26 | + </div> | |
27 | + </div> | |
28 | + <?php $js = "$('#$class').owlCarousel({ | |
29 | +navigation:true, | |
30 | +navigationText: [] | |
31 | +}) | |
32 | +"; | |
33 | + $this->registerJs($js, View::POS_READY); | |
34 | + ?> | |
35 | +<?php } ?> | |
0 | 36 | \ No newline at end of file | ... | ... |
1 | +++ a/artbox-ecommerce/widgets/views/submenu.php | |
1 | +<?php | |
2 | + /** | |
3 | + * @var Category $rootCategory | |
4 | + * @var string $rootClass | |
5 | + */ | |
6 | + use artweb\artbox\ecommerce\models\Category; | |
7 | + | |
8 | +?> | |
9 | +<div class="menu_item"> | |
10 | + <?= \yii\helpers\Html::a($rootCategory->lang->title, [ | |
11 | + 'catalog/category', | |
12 | + 'category' => $rootCategory, | |
13 | + ], [ 'class' => 'submenu_button ' . $rootClass ]) ?> | |
14 | + <div class="submenu"> | |
15 | + <ul class="categories"> | |
16 | + <?php foreach($items as $item) : ?> | |
17 | + <li class="sub_cat"> | |
18 | + <span><?= $item[ 'item' ]->title ?></span> | |
19 | + <?php if(!empty( $item[ 'children' ] )) : ?> | |
20 | + <div class="sub_cat_content"> | |
21 | + <div class="content_items"> | |
22 | + <?php foreach($item[ 'children' ] as $_item) : ?> | |
23 | + <div class="content_item"><a href="<?= \yii\helpers\Url::to([ | |
24 | + 'catalog/category', | |
25 | + 'category' => $_item[ 'item' ], | |
26 | + ]) ?>"> | |
27 | + <div class="picture"> | |
28 | + <?php if(empty( $_item[ 'item' ]->image )) : ?> | |
29 | + <img src="/images/no_photo.png"> | |
30 | + <?php else : ?> | |
31 | + <?= $_item[ 'item' ]->imageUrl ? \common\components\artboximage\ArtboxImageHelper::getImage($_item[ 'item' ]->imageUrl, 'mainmenu') : '' ?> | |
32 | + <?php endif ?> | |
33 | + </div> | |
34 | + <div class="title"><?= $_item[ 'item' ]->title ?></div> | |
35 | + </a></div> | |
36 | + <?php endforeach ?> | |
37 | + </div> | |
38 | + </div> | |
39 | + <?php endif ?> | |
40 | + </li> | |
41 | + <?php endforeach ?> | |
42 | + </ul> | |
43 | + </div> | |
44 | +</div> | ... | ... |
1 | +++ a/artbox-file/FileUploadAsset.php | |
1 | +<?php | |
2 | +/** | |
3 | + * @link http://www.yiiframework.com/ | |
4 | + * @copyright Copyright (c) 2008 Yii Software LLC | |
5 | + * @license http://www.yiiframework.com/license/ | |
6 | + */ | |
7 | + | |
8 | + | |
9 | +namespace artweb\artbox\file; | |
10 | + | |
11 | +use yii\helpers\Url; | |
12 | +use yii\web\AssetBundle; | |
13 | + | |
14 | +/** | |
15 | + * Asset bundle for the Twitter bootstrap javascript files. | |
16 | + * | |
17 | + * @author Qiang Xue <qiang.xue@gmail.com> | |
18 | + * @since 2.0 | |
19 | + */ | |
20 | +class FileUploadAsset extends AssetBundle | |
21 | +{ | |
22 | + | |
23 | + | |
24 | + /** | |
25 | + * @inheritdoc | |
26 | + */ | |
27 | + public function init() | |
28 | + { | |
29 | + parent::init(); | |
30 | + $this->sourcePath = __DIR__.'/assets'; | |
31 | + } | |
32 | + | |
33 | + public $css = [ | |
34 | + 'css/jquery.fileupload.css', | |
35 | + 'css/fileupload/style.css' | |
36 | + ]; | |
37 | + | |
38 | + public $js = [ | |
39 | + 'js/vendor/jquery.ui.widget.js', | |
40 | + 'js/jquery.iframe-transport.js', | |
41 | + 'js/jquery.fileupload.js' | |
42 | + ]; | |
43 | +} | ... | ... |
1 | +++ a/artbox-file/Module.php | |
1 | +<?php | |
2 | +namespace artweb\artbox\file; | |
3 | + | |
4 | +use yii\base\BootstrapInterface; | |
5 | + | |
6 | +class Module extends \yii\base\Module | |
7 | +{ | |
8 | + public function init() | |
9 | + { | |
10 | + parent::init(); | |
11 | + | |
12 | + \Yii::configure($this, require(__DIR__.'/config.php')); | |
13 | + } | |
14 | + | |
15 | +} | ... | ... |
artbox-file/assets/css/jquery.fileupload-noscript.css
0 → 100755
1 | +++ a/artbox-file/assets/css/jquery.fileupload-noscript.css | |
1 | +@charset "UTF-8"; | |
2 | +/* | |
3 | + * jQuery File Upload Plugin NoScript CSS | |
4 | + * https://github.com/blueimp/jQuery-File-Upload | |
5 | + * | |
6 | + * Copyright 2013, Sebastian Tschan | |
7 | + * https://blueimp.net | |
8 | + * | |
9 | + * Licensed under the MIT license: | |
10 | + * http://www.opensource.org/licenses/MIT | |
11 | + */ | |
12 | + | |
13 | +.fileinput-button input { | |
14 | + position: static; | |
15 | + opacity: 1; | |
16 | + filter: none; | |
17 | + font-size: inherit; | |
18 | + direction: inherit; | |
19 | +} | |
20 | +.fileinput-button span { | |
21 | + display: none; | |
22 | +} | ... | ... |
artbox-file/assets/css/jquery.fileupload-ui-noscript.css
0 → 100755
1 | +++ a/artbox-file/assets/css/jquery.fileupload-ui-noscript.css | |
1 | +@charset "UTF-8"; | |
2 | +/* | |
3 | + * jQuery File Upload UI Plugin NoScript CSS | |
4 | + * https://github.com/blueimp/jQuery-File-Upload | |
5 | + * | |
6 | + * Copyright 2012, Sebastian Tschan | |
7 | + * https://blueimp.net | |
8 | + * | |
9 | + * Licensed under the MIT license: | |
10 | + * http://www.opensource.org/licenses/MIT | |
11 | + */ | |
12 | + | |
13 | +.fileinput-button i, | |
14 | +.fileupload-buttonbar .delete, | |
15 | +.fileupload-buttonbar .toggle { | |
16 | + display: none; | |
17 | +} | ... | ... |
1 | +++ a/artbox-file/assets/css/jquery.fileupload-ui.css | |
1 | +@charset "UTF-8"; | |
2 | +/* | |
3 | + * jQuery File Upload UI Plugin CSS | |
4 | + * https://github.com/blueimp/jQuery-File-Upload | |
5 | + * | |
6 | + * Copyright 2010, Sebastian Tschan | |
7 | + * https://blueimp.net | |
8 | + * | |
9 | + * Licensed under the MIT license: | |
10 | + * http://www.opensource.org/licenses/MIT | |
11 | + */ | |
12 | + | |
13 | +.fileupload-buttonbar .btn, | |
14 | +.fileupload-buttonbar .toggle { | |
15 | + margin-bottom: 5px; | |
16 | +} | |
17 | +.progress-animated .progress-bar, | |
18 | +.progress-animated .bar { | |
19 | + background: url("../img/progressbar.gif") !important; | |
20 | + filter: none; | |
21 | +} | |
22 | +.fileupload-process { | |
23 | + float: right; | |
24 | + display: none; | |
25 | +} | |
26 | +.fileupload-processing .fileupload-process, | |
27 | +.files .processing .preview { | |
28 | + display: block; | |
29 | + width: 32px; | |
30 | + height: 32px; | |
31 | + background: url("../img/loading.gif") center no-repeat; | |
32 | + background-size: contain; | |
33 | +} | |
34 | +.files audio, | |
35 | +.files video { | |
36 | + max-width: 300px; | |
37 | +} | |
38 | + | |
39 | +@media (max-width: 767px) { | |
40 | + .fileupload-buttonbar .toggle, | |
41 | + .files .toggle, | |
42 | + .files .btn span { | |
43 | + display: none; | |
44 | + } | |
45 | + .files .name { | |
46 | + width: 80px; | |
47 | + word-wrap: break-word; | |
48 | + } | |
49 | + .files audio, | |
50 | + .files video { | |
51 | + max-width: 80px; | |
52 | + } | |
53 | + .files img, | |
54 | + .files canvas { | |
55 | + max-width: 100%; | |
56 | + } | |
57 | +} | ... | ... |
1 | +++ a/artbox-file/assets/css/jquery.fileupload.css | |
1 | +@charset "UTF-8"; | |
2 | +/* | |
3 | + * jQuery File Upload Plugin CSS | |
4 | + * https://github.com/blueimp/jQuery-File-Upload | |
5 | + * | |
6 | + * Copyright 2013, Sebastian Tschan | |
7 | + * https://blueimp.net | |
8 | + * | |
9 | + * Licensed under the MIT license: | |
10 | + * http://www.opensource.org/licenses/MIT | |
11 | + */ | |
12 | + | |
13 | +.fileinput-button { | |
14 | + position: relative; | |
15 | + overflow: hidden; | |
16 | + display: inline-block; | |
17 | +} | |
18 | +.fileinput-button input { | |
19 | + position: absolute; | |
20 | + top: 0; | |
21 | + right: 0; | |
22 | + margin: 0; | |
23 | + opacity: 0; | |
24 | + -ms-filter: 'alpha(opacity=0)'; | |
25 | + font-size: 200px; | |
26 | + direction: ltr; | |
27 | + cursor: pointer; | |
28 | +} | |
29 | + | |
30 | +/* Fixes for IE < 8 */ | |
31 | +@media screen\9 { | |
32 | + .fileinput-button input { | |
33 | + filter: alpha(opacity=0); | |
34 | + font-size: 100%; | |
35 | + height: 100%; | |
36 | + } | |
37 | +} | ... | ... |
3.81 KB
3.25 KB
artbox-file/assets/js/cors/jquery.postmessage-transport.js
0 → 100755
1 | +++ a/artbox-file/assets/js/cors/jquery.postmessage-transport.js | |
1 | +/* | |
2 | + * jQuery postMessage Transport Plugin | |
3 | + * https://github.com/blueimp/jQuery-File-Upload | |
4 | + * | |
5 | + * Copyright 2011, Sebastian Tschan | |
6 | + * https://blueimp.net | |
7 | + * | |
8 | + * Licensed under the MIT license: | |
9 | + * http://www.opensource.org/licenses/MIT | |
10 | + */ | |
11 | + | |
12 | +/* global define, require, window, document */ | |
13 | + | |
14 | +(function (factory) { | |
15 | + 'use strict'; | |
16 | + if (typeof define === 'function' && define.amd) { | |
17 | + // Register as an anonymous AMD module: | |
18 | + define(['jquery'], factory); | |
19 | + } else if (typeof exports === 'object') { | |
20 | + // Node/CommonJS: | |
21 | + factory(require('jquery')); | |
22 | + } else { | |
23 | + // Browser globals: | |
24 | + factory(window.jQuery); | |
25 | + } | |
26 | +}(function ($) { | |
27 | + 'use strict'; | |
28 | + | |
29 | + var counter = 0, | |
30 | + names = [ | |
31 | + 'accepts', | |
32 | + 'cache', | |
33 | + 'contents', | |
34 | + 'contentType', | |
35 | + 'crossDomain', | |
36 | + 'data', | |
37 | + 'dataType', | |
38 | + 'headers', | |
39 | + 'ifModified', | |
40 | + 'mimeType', | |
41 | + 'password', | |
42 | + 'processData', | |
43 | + 'timeout', | |
44 | + 'traditional', | |
45 | + 'type', | |
46 | + 'url', | |
47 | + 'username' | |
48 | + ], | |
49 | + convert = function (p) { | |
50 | + return p; | |
51 | + }; | |
52 | + | |
53 | + $.ajaxSetup({ | |
54 | + converters: { | |
55 | + 'postmessage text': convert, | |
56 | + 'postmessage json': convert, | |
57 | + 'postmessage html': convert | |
58 | + } | |
59 | + }); | |
60 | + | |
61 | + $.ajaxTransport('postmessage', function (options) { | |
62 | + if (options.postMessage && window.postMessage) { | |
63 | + var iframe, | |
64 | + loc = $('<a>').prop('href', options.postMessage)[0], | |
65 | + target = loc.protocol + '//' + loc.host, | |
66 | + xhrUpload = options.xhr().upload; | |
67 | + return { | |
68 | + send: function (_, completeCallback) { | |
69 | + counter += 1; | |
70 | + var message = { | |
71 | + id: 'postmessage-transport-' + counter | |
72 | + }, | |
73 | + eventName = 'message.' + message.id; | |
74 | + iframe = $( | |
75 | + '<iframe style="display:none;" src="' + | |
76 | + options.postMessage + '" name="' + | |
77 | + message.id + '"></iframe>' | |
78 | + ).bind('load', function () { | |
79 | + $.each(names, function (i, name) { | |
80 | + message[name] = options[name]; | |
81 | + }); | |
82 | + message.dataType = message.dataType.replace('postmessage ', ''); | |
83 | + $(window).bind(eventName, function (e) { | |
84 | + e = e.originalEvent; | |
85 | + var data = e.data, | |
86 | + ev; | |
87 | + if (e.origin === target && data.id === message.id) { | |
88 | + if (data.type === 'progress') { | |
89 | + ev = document.createEvent('Event'); | |
90 | + ev.initEvent(data.type, false, true); | |
91 | + $.extend(ev, data); | |
92 | + xhrUpload.dispatchEvent(ev); | |
93 | + } else { | |
94 | + completeCallback( | |
95 | + data.status, | |
96 | + data.statusText, | |
97 | + {postmessage: data.result}, | |
98 | + data.headers | |
99 | + ); | |
100 | + iframe.remove(); | |
101 | + $(window).unbind(eventName); | |
102 | + } | |
103 | + } | |
104 | + }); | |
105 | + iframe[0].contentWindow.postMessage( | |
106 | + message, | |
107 | + target | |
108 | + ); | |
109 | + }).appendTo(document.body); | |
110 | + }, | |
111 | + abort: function () { | |
112 | + if (iframe) { | |
113 | + iframe.remove(); | |
114 | + } | |
115 | + } | |
116 | + }; | |
117 | + } | |
118 | + }); | |
119 | + | |
120 | +})); | ... | ... |
1 | +++ a/artbox-file/assets/js/cors/jquery.xdr-transport.js | |
1 | +/* | |
2 | + * jQuery XDomainRequest Transport Plugin | |
3 | + * https://github.com/blueimp/jQuery-File-Upload | |
4 | + * | |
5 | + * Copyright 2011, Sebastian Tschan | |
6 | + * https://blueimp.net | |
7 | + * | |
8 | + * Licensed under the MIT license: | |
9 | + * http://www.opensource.org/licenses/MIT | |
10 | + * | |
11 | + * Based on Julian Aubourg's ajaxHooks xdr.js: | |
12 | + * https://github.com/jaubourg/ajaxHooks/ | |
13 | + */ | |
14 | + | |
15 | +/* global define, require, window, XDomainRequest */ | |
16 | + | |
17 | +(function (factory) { | |
18 | + 'use strict'; | |
19 | + if (typeof define === 'function' && define.amd) { | |
20 | + // Register as an anonymous AMD module: | |
21 | + define(['jquery'], factory); | |
22 | + } else if (typeof exports === 'object') { | |
23 | + // Node/CommonJS: | |
24 | + factory(require('jquery')); | |
25 | + } else { | |
26 | + // Browser globals: | |
27 | + factory(window.jQuery); | |
28 | + } | |
29 | +}(function ($) { | |
30 | + 'use strict'; | |
31 | + if (window.XDomainRequest && !$.support.cors) { | |
32 | + $.ajaxTransport(function (s) { | |
33 | + if (s.crossDomain && s.async) { | |
34 | + if (s.timeout) { | |
35 | + s.xdrTimeout = s.timeout; | |
36 | + delete s.timeout; | |
37 | + } | |
38 | + var xdr; | |
39 | + return { | |
40 | + send: function (headers, completeCallback) { | |
41 | + var addParamChar = /\?/.test(s.url) ? '&' : '?'; | |
42 | + function callback(status, statusText, responses, responseHeaders) { | |
43 | + xdr.onload = xdr.onerror = xdr.ontimeout = $.noop; | |
44 | + xdr = null; | |
45 | + completeCallback(status, statusText, responses, responseHeaders); | |
46 | + } | |
47 | + xdr = new XDomainRequest(); | |
48 | + // XDomainRequest only supports GET and POST: | |
49 | + if (s.type === 'DELETE') { | |
50 | + s.url = s.url + addParamChar + '_method=DELETE'; | |
51 | + s.type = 'POST'; | |
52 | + } else if (s.type === 'PUT') { | |
53 | + s.url = s.url + addParamChar + '_method=PUT'; | |
54 | + s.type = 'POST'; | |
55 | + } else if (s.type === 'PATCH') { | |
56 | + s.url = s.url + addParamChar + '_method=PATCH'; | |
57 | + s.type = 'POST'; | |
58 | + } | |
59 | + xdr.open(s.type, s.url); | |
60 | + xdr.onload = function () { | |
61 | + callback( | |
62 | + 200, | |
63 | + 'OK', | |
64 | + {text: xdr.responseText}, | |
65 | + 'Content-Type: ' + xdr.contentType | |
66 | + ); | |
67 | + }; | |
68 | + xdr.onerror = function () { | |
69 | + callback(404, 'Not Found'); | |
70 | + }; | |
71 | + if (s.xdrTimeout) { | |
72 | + xdr.ontimeout = function () { | |
73 | + callback(0, 'timeout'); | |
74 | + }; | |
75 | + xdr.timeout = s.xdrTimeout; | |
76 | + } | |
77 | + xdr.send((s.hasContent && s.data) || null); | |
78 | + }, | |
79 | + abort: function () { | |
80 | + if (xdr) { | |
81 | + xdr.onerror = $.noop(); | |
82 | + xdr.abort(); | |
83 | + } | |
84 | + } | |
85 | + }; | |
86 | + } | |
87 | + }); | |
88 | + } | |
89 | +})); | ... | ... |
1 | +++ a/artbox-file/assets/js/jquery.fileupload-angular.js | |
1 | +/* | |
2 | + * jQuery File Upload AngularJS Plugin | |
3 | + * https://github.com/blueimp/jQuery-File-Upload | |
4 | + * | |
5 | + * Copyright 2013, Sebastian Tschan | |
6 | + * https://blueimp.net | |
7 | + * | |
8 | + * Licensed under the MIT license: | |
9 | + * http://www.opensource.org/licenses/MIT | |
10 | + */ | |
11 | + | |
12 | +/* jshint nomen:false */ | |
13 | +/* global define, angular */ | |
14 | + | |
15 | +(function (factory) { | |
16 | + 'use strict'; | |
17 | + if (typeof define === 'function' && define.amd) { | |
18 | + // Register as an anonymous AMD module: | |
19 | + define([ | |
20 | + 'jquery', | |
21 | + 'angular', | |
22 | + './jquery.fileupload-image', | |
23 | + './jquery.fileupload-audio', | |
24 | + './jquery.fileupload-video', | |
25 | + './jquery.fileupload-validate' | |
26 | + ], factory); | |
27 | + } else { | |
28 | + factory(); | |
29 | + } | |
30 | +}(function () { | |
31 | + 'use strict'; | |
32 | + | |
33 | + angular.module('blueimp.fileupload', []) | |
34 | + | |
35 | + // The fileUpload service provides configuration options | |
36 | + // for the fileUpload directive and default handlers for | |
37 | + // File Upload events: | |
38 | + .provider('fileUpload', function () { | |
39 | + var scopeEvalAsync = function (expression) { | |
40 | + var scope = angular.element(this) | |
41 | + .fileupload('option', 'scope'); | |
42 | + // Schedule a new $digest cycle if not already inside of one | |
43 | + // and evaluate the given expression: | |
44 | + scope.$evalAsync(expression); | |
45 | + }, | |
46 | + addFileMethods = function (scope, data) { | |
47 | + var files = data.files, | |
48 | + file = files[0]; | |
49 | + angular.forEach(files, function (file, index) { | |
50 | + file._index = index; | |
51 | + file.$state = function () { | |
52 | + return data.state(); | |
53 | + }; | |
54 | + file.$processing = function () { | |
55 | + return data.processing(); | |
56 | + }; | |
57 | + file.$progress = function () { | |
58 | + return data.progress(); | |
59 | + }; | |
60 | + file.$response = function () { | |
61 | + return data.response(); | |
62 | + }; | |
63 | + }); | |
64 | + file.$submit = function () { | |
65 | + if (!file.error) { | |
66 | + return data.submit(); | |
67 | + } | |
68 | + }; | |
69 | + file.$cancel = function () { | |
70 | + return data.abort(); | |
71 | + }; | |
72 | + }, | |
73 | + $config; | |
74 | + $config = this.defaults = { | |
75 | + handleResponse: function (e, data) { | |
76 | + var files = data.result && data.result.files; | |
77 | + if (files) { | |
78 | + data.scope.replace(data.files, files); | |
79 | + } else if (data.errorThrown || | |
80 | + data.textStatus === 'error') { | |
81 | + data.files[0].error = data.errorThrown || | |
82 | + data.textStatus; | |
83 | + } | |
84 | + }, | |
85 | + add: function (e, data) { | |
86 | + if (e.isDefaultPrevented()) { | |
87 | + return false; | |
88 | + } | |
89 | + var scope = data.scope, | |
90 | + filesCopy = []; | |
91 | + angular.forEach(data.files, function (file) { | |
92 | + filesCopy.push(file); | |
93 | + }); | |
94 | + scope.$parent.$applyAsync(function () { | |
95 | + addFileMethods(scope, data); | |
96 | + var method = scope.option('prependFiles') ? | |
97 | + 'unshift' : 'push'; | |
98 | + Array.prototype[method].apply(scope.queue, data.files); | |
99 | + }); | |
100 | + data.process(function () { | |
101 | + return scope.process(data); | |
102 | + }).always(function () { | |
103 | + scope.$parent.$applyAsync(function () { | |
104 | + addFileMethods(scope, data); | |
105 | + scope.replace(filesCopy, data.files); | |
106 | + }); | |
107 | + }).then(function () { | |
108 | + if ((scope.option('autoUpload') || | |
109 | + data.autoUpload) && | |
110 | + data.autoUpload !== false) { | |
111 | + data.submit(); | |
112 | + } | |
113 | + }); | |
114 | + }, | |
115 | + done: function (e, data) { | |
116 | + if (e.isDefaultPrevented()) { | |
117 | + return false; | |
118 | + } | |
119 | + var that = this; | |
120 | + data.scope.$apply(function () { | |
121 | + data.handleResponse.call(that, e, data); | |
122 | + }); | |
123 | + }, | |
124 | + fail: function (e, data) { | |
125 | + if (e.isDefaultPrevented()) { | |
126 | + return false; | |
127 | + } | |
128 | + var that = this, | |
129 | + scope = data.scope; | |
130 | + if (data.errorThrown === 'abort') { | |
131 | + scope.clear(data.files); | |
132 | + return; | |
133 | + } | |
134 | + scope.$apply(function () { | |
135 | + data.handleResponse.call(that, e, data); | |
136 | + }); | |
137 | + }, | |
138 | + stop: scopeEvalAsync, | |
139 | + processstart: scopeEvalAsync, | |
140 | + processstop: scopeEvalAsync, | |
141 | + getNumberOfFiles: function () { | |
142 | + var scope = this.scope; | |
143 | + return scope.queue.length - scope.processing(); | |
144 | + }, | |
145 | + dataType: 'json', | |
146 | + autoUpload: false | |
147 | + }; | |
148 | + this.$get = [ | |
149 | + function () { | |
150 | + return { | |
151 | + defaults: $config | |
152 | + }; | |
153 | + } | |
154 | + ]; | |
155 | + }) | |
156 | + | |
157 | + // Format byte numbers to readable presentations: | |
158 | + .provider('formatFileSizeFilter', function () { | |
159 | + var $config = { | |
160 | + // Byte units following the IEC format | |
161 | + // http://en.wikipedia.org/wiki/Kilobyte | |
162 | + units: [ | |
163 | + {size: 1000000000, suffix: ' GB'}, | |
164 | + {size: 1000000, suffix: ' MB'}, | |
165 | + {size: 1000, suffix: ' KB'} | |
166 | + ] | |
167 | + }; | |
168 | + this.defaults = $config; | |
169 | + this.$get = function () { | |
170 | + return function (bytes) { | |
171 | + if (!angular.isNumber(bytes)) { | |
172 | + return ''; | |
173 | + } | |
174 | + var unit = true, | |
175 | + i = 0, | |
176 | + prefix, | |
177 | + suffix; | |
178 | + while (unit) { | |
179 | + unit = $config.units[i]; | |
180 | + prefix = unit.prefix || ''; | |
181 | + suffix = unit.suffix || ''; | |
182 | + if (i === $config.units.length - 1 || bytes >= unit.size) { | |
183 | + return prefix + (bytes / unit.size).toFixed(2) + suffix; | |
184 | + } | |
185 | + i += 1; | |
186 | + } | |
187 | + }; | |
188 | + }; | |
189 | + }) | |
190 | + | |
191 | + // The FileUploadController initializes the fileupload widget and | |
192 | + // provides scope methods to control the File Upload functionality: | |
193 | + .controller('FileUploadController', [ | |
194 | + '$scope', '$element', '$attrs', '$window', 'fileUpload', | |
195 | + function ($scope, $element, $attrs, $window, fileUpload) { | |
196 | + var uploadMethods = { | |
197 | + progress: function () { | |
198 | + return $element.fileupload('progress'); | |
199 | + }, | |
200 | + active: function () { | |
201 | + return $element.fileupload('active'); | |
202 | + }, | |
203 | + option: function (option, data) { | |
204 | + if (arguments.length === 1) { | |
205 | + return $element.fileupload('option', option); | |
206 | + } | |
207 | + $element.fileupload('option', option, data); | |
208 | + }, | |
209 | + add: function (data) { | |
210 | + return $element.fileupload('add', data); | |
211 | + }, | |
212 | + send: function (data) { | |
213 | + return $element.fileupload('send', data); | |
214 | + }, | |
215 | + process: function (data) { | |
216 | + return $element.fileupload('process', data); | |
217 | + }, | |
218 | + processing: function (data) { | |
219 | + return $element.fileupload('processing', data); | |
220 | + } | |
221 | + }; | |
222 | + $scope.disabled = !$window.jQuery.support.fileInput; | |
223 | + $scope.queue = $scope.queue || []; | |
224 | + $scope.clear = function (files) { | |
225 | + var queue = this.queue, | |
226 | + i = queue.length, | |
227 | + file = files, | |
228 | + length = 1; | |
229 | + if (angular.isArray(files)) { | |
230 | + file = files[0]; | |
231 | + length = files.length; | |
232 | + } | |
233 | + while (i) { | |
234 | + i -= 1; | |
235 | + if (queue[i] === file) { | |
236 | + return queue.splice(i, length); | |
237 | + } | |
238 | + } | |
239 | + }; | |
240 | + $scope.replace = function (oldFiles, newFiles) { | |
241 | + var queue = this.queue, | |
242 | + file = oldFiles[0], | |
243 | + i, | |
244 | + j; | |
245 | + for (i = 0; i < queue.length; i += 1) { | |
246 | + if (queue[i] === file) { | |
247 | + for (j = 0; j < newFiles.length; j += 1) { | |
248 | + queue[i + j] = newFiles[j]; | |
249 | + } | |
250 | + return; | |
251 | + } | |
252 | + } | |
253 | + }; | |
254 | + $scope.applyOnQueue = function (method) { | |
255 | + var list = this.queue.slice(0), | |
256 | + i, | |
257 | + file; | |
258 | + for (i = 0; i < list.length; i += 1) { | |
259 | + file = list[i]; | |
260 | + if (file[method]) { | |
261 | + file[method](); | |
262 | + } | |
263 | + } | |
264 | + }; | |
265 | + $scope.submit = function () { | |
266 | + this.applyOnQueue('$submit'); | |
267 | + }; | |
268 | + $scope.cancel = function () { | |
269 | + this.applyOnQueue('$cancel'); | |
270 | + }; | |
271 | + // Add upload methods to the scope: | |
272 | + angular.extend($scope, uploadMethods); | |
273 | + // The fileupload widget will initialize with | |
274 | + // the options provided via "data-"-parameters, | |
275 | + // as well as those given via options object: | |
276 | + $element.fileupload(angular.extend( | |
277 | + {scope: $scope}, | |
278 | + fileUpload.defaults | |
279 | + )).on('fileuploadadd', function (e, data) { | |
280 | + data.scope = $scope; | |
281 | + }).on('fileuploadfail', function (e, data) { | |
282 | + if (data.errorThrown === 'abort') { | |
283 | + return; | |
284 | + } | |
285 | + if (data.dataType && | |
286 | + data.dataType.indexOf('json') === data.dataType.length - 4) { | |
287 | + try { | |
288 | + data.result = angular.fromJson(data.jqXHR.responseText); | |
289 | + } catch (ignore) {} | |
290 | + } | |
291 | + }).on([ | |
292 | + 'fileuploadadd', | |
293 | + 'fileuploadsubmit', | |
294 | + 'fileuploadsend', | |
295 | + 'fileuploaddone', | |
296 | + 'fileuploadfail', | |
297 | + 'fileuploadalways', | |
298 | + 'fileuploadprogress', | |
299 | + 'fileuploadprogressall', | |
300 | + 'fileuploadstart', | |
301 | + 'fileuploadstop', | |
302 | + 'fileuploadchange', | |
303 | + 'fileuploadpaste', | |
304 | + 'fileuploaddrop', | |
305 | + 'fileuploaddragover', | |
306 | + 'fileuploadchunksend', | |
307 | + 'fileuploadchunkdone', | |
308 | + 'fileuploadchunkfail', | |
309 | + 'fileuploadchunkalways', | |
310 | + 'fileuploadprocessstart', | |
311 | + 'fileuploadprocess', | |
312 | + 'fileuploadprocessdone', | |
313 | + 'fileuploadprocessfail', | |
314 | + 'fileuploadprocessalways', | |
315 | + 'fileuploadprocessstop' | |
316 | + ].join(' '), function (e, data) { | |
317 | + $scope.$parent.$applyAsync(function () { | |
318 | + if ($scope.$emit(e.type, data).defaultPrevented) { | |
319 | + e.preventDefault(); | |
320 | + } | |
321 | + }); | |
322 | + }).on('remove', function () { | |
323 | + // Remove upload methods from the scope, | |
324 | + // when the widget is removed: | |
325 | + var method; | |
326 | + for (method in uploadMethods) { | |
327 | + if (uploadMethods.hasOwnProperty(method)) { | |
328 | + delete $scope[method]; | |
329 | + } | |
330 | + } | |
331 | + }); | |
332 | + // Observe option changes: | |
333 | + $scope.$watch( | |
334 | + $attrs.fileUpload, | |
335 | + function (newOptions) { | |
336 | + if (newOptions) { | |
337 | + $element.fileupload('option', newOptions); | |
338 | + } | |
339 | + } | |
340 | + ); | |
341 | + } | |
342 | + ]) | |
343 | + | |
344 | + // Provide File Upload progress feedback: | |
345 | + .controller('FileUploadProgressController', [ | |
346 | + '$scope', '$attrs', '$parse', | |
347 | + function ($scope, $attrs, $parse) { | |
348 | + var fn = $parse($attrs.fileUploadProgress), | |
349 | + update = function () { | |
350 | + var progress = fn($scope); | |
351 | + if (!progress || !progress.total) { | |
352 | + return; | |
353 | + } | |
354 | + $scope.num = Math.floor( | |
355 | + progress.loaded / progress.total * 100 | |
356 | + ); | |
357 | + }; | |
358 | + update(); | |
359 | + $scope.$watch( | |
360 | + $attrs.fileUploadProgress + '.loaded', | |
361 | + function (newValue, oldValue) { | |
362 | + if (newValue !== oldValue) { | |
363 | + update(); | |
364 | + } | |
365 | + } | |
366 | + ); | |
367 | + } | |
368 | + ]) | |
369 | + | |
370 | + // Display File Upload previews: | |
371 | + .controller('FileUploadPreviewController', [ | |
372 | + '$scope', '$element', '$attrs', | |
373 | + function ($scope, $element, $attrs) { | |
374 | + $scope.$watch( | |
375 | + $attrs.fileUploadPreview + '.preview', | |
376 | + function (preview) { | |
377 | + $element.empty(); | |
378 | + if (preview) { | |
379 | + $element.append(preview); | |
380 | + } | |
381 | + } | |
382 | + ); | |
383 | + } | |
384 | + ]) | |
385 | + | |
386 | + .directive('fileUpload', function () { | |
387 | + return { | |
388 | + controller: 'FileUploadController', | |
389 | + scope: true | |
390 | + }; | |
391 | + }) | |
392 | + | |
393 | + .directive('fileUploadProgress', function () { | |
394 | + return { | |
395 | + controller: 'FileUploadProgressController', | |
396 | + scope: true | |
397 | + }; | |
398 | + }) | |
399 | + | |
400 | + .directive('fileUploadPreview', function () { | |
401 | + return { | |
402 | + controller: 'FileUploadPreviewController' | |
403 | + }; | |
404 | + }) | |
405 | + | |
406 | + // Enhance the HTML5 download attribute to | |
407 | + // allow drag&drop of files to the desktop: | |
408 | + .directive('download', function () { | |
409 | + return function (scope, elm) { | |
410 | + elm.on('dragstart', function (e) { | |
411 | + try { | |
412 | + e.originalEvent.dataTransfer.setData( | |
413 | + 'DownloadURL', | |
414 | + [ | |
415 | + 'application/octet-stream', | |
416 | + elm.prop('download'), | |
417 | + elm.prop('href') | |
418 | + ].join(':') | |
419 | + ); | |
420 | + } catch (ignore) {} | |
421 | + }); | |
422 | + }; | |
423 | + }); | |
424 | + | |
425 | +})); | ... | ... |
1 | +++ a/artbox-file/assets/js/jquery.fileupload-audio.js | |
1 | +/* | |
2 | + * jQuery File Upload Audio Preview Plugin | |
3 | + * https://github.com/blueimp/jQuery-File-Upload | |
4 | + * | |
5 | + * Copyright 2013, Sebastian Tschan | |
6 | + * https://blueimp.net | |
7 | + * | |
8 | + * Licensed under the MIT license: | |
9 | + * http://www.opensource.org/licenses/MIT | |
10 | + */ | |
11 | + | |
12 | +/* jshint nomen:false */ | |
13 | +/* global define, require, window, document */ | |
14 | + | |
15 | +(function (factory) { | |
16 | + 'use strict'; | |
17 | + if (typeof define === 'function' && define.amd) { | |
18 | + // Register as an anonymous AMD module: | |
19 | + define([ | |
20 | + 'jquery', | |
21 | + 'load-image', | |
22 | + './jquery.fileupload-process' | |
23 | + ], factory); | |
24 | + } else if (typeof exports === 'object') { | |
25 | + // Node/CommonJS: | |
26 | + factory( | |
27 | + require('jquery'), | |
28 | + require('load-image') | |
29 | + ); | |
30 | + } else { | |
31 | + // Browser globals: | |
32 | + factory( | |
33 | + window.jQuery, | |
34 | + window.loadImage | |
35 | + ); | |
36 | + } | |
37 | +}(function ($, loadImage) { | |
38 | + 'use strict'; | |
39 | + | |
40 | + // Prepend to the default processQueue: | |
41 | + $.blueimp.fileupload.prototype.options.processQueue.unshift( | |
42 | + { | |
43 | + action: 'loadAudio', | |
44 | + // Use the action as prefix for the "@" options: | |
45 | + prefix: true, | |
46 | + fileTypes: '@', | |
47 | + maxFileSize: '@', | |
48 | + disabled: '@disableAudioPreview' | |
49 | + }, | |
50 | + { | |
51 | + action: 'setAudio', | |
52 | + name: '@audioPreviewName', | |
53 | + disabled: '@disableAudioPreview' | |
54 | + } | |
55 | + ); | |
56 | + | |
57 | + // The File Upload Audio Preview plugin extends the fileupload widget | |
58 | + // with audio preview functionality: | |
59 | + $.widget('blueimp.fileupload', $.blueimp.fileupload, { | |
60 | + | |
61 | + options: { | |
62 | + // The regular expression for the types of audio files to load, | |
63 | + // matched against the file type: | |
64 | + loadAudioFileTypes: /^audio\/.*$/ | |
65 | + }, | |
66 | + | |
67 | + _audioElement: document.createElement('audio'), | |
68 | + | |
69 | + processActions: { | |
70 | + | |
71 | + // Loads the audio file given via data.files and data.index | |
72 | + // as audio element if the browser supports playing it. | |
73 | + // Accepts the options fileTypes (regular expression) | |
74 | + // and maxFileSize (integer) to limit the files to load: | |
75 | + loadAudio: function (data, options) { | |
76 | + if (options.disabled) { | |
77 | + return data; | |
78 | + } | |
79 | + var file = data.files[data.index], | |
80 | + url, | |
81 | + audio; | |
82 | + if (this._audioElement.canPlayType && | |
83 | + this._audioElement.canPlayType(file.type) && | |
84 | + ($.type(options.maxFileSize) !== 'number' || | |
85 | + file.size <= options.maxFileSize) && | |
86 | + (!options.fileTypes || | |
87 | + options.fileTypes.test(file.type))) { | |
88 | + url = loadImage.createObjectURL(file); | |
89 | + if (url) { | |
90 | + audio = this._audioElement.cloneNode(false); | |
91 | + audio.src = url; | |
92 | + audio.controls = true; | |
93 | + data.audio = audio; | |
94 | + return data; | |
95 | + } | |
96 | + } | |
97 | + return data; | |
98 | + }, | |
99 | + | |
100 | + // Sets the audio element as a property of the file object: | |
101 | + setAudio: function (data, options) { | |
102 | + if (data.audio && !options.disabled) { | |
103 | + data.files[data.index][options.name || 'preview'] = data.audio; | |
104 | + } | |
105 | + return data; | |
106 | + } | |
107 | + | |
108 | + } | |
109 | + | |
110 | + }); | |
111 | + | |
112 | +})); | ... | ... |