1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace app\modules\shop\models; |
4
|
|
|
|
5
|
|
|
use app\behaviors\CleanRelations; |
6
|
|
|
use app\behaviors\Tree; |
7
|
|
|
use app\components\Helper; |
8
|
|
|
use app\modules\image\models\Image; |
9
|
|
|
use app\models\BaseObject; |
10
|
|
|
use app\modules\data\components\ImportableInterface; |
11
|
|
|
use app\modules\data\components\ExportableInterface; |
12
|
|
|
use app\modules\shop\data\FilterPagination; |
13
|
|
|
use app\modules\shop\traits\HasAddonTrait; |
14
|
|
|
use app\modules\shop\ShopModule; |
15
|
|
|
use app\properties\HasProperties; |
16
|
|
|
use app\properties\PropertiesHelper; |
17
|
|
|
use app\traits\GetImages; |
18
|
|
|
use devgroup\TagDependencyHelper\ActiveRecordHelper; |
19
|
|
|
use Yii; |
20
|
|
|
use yii\base\Exception; |
21
|
|
|
use yii\behaviors\TimestampBehavior; |
22
|
|
|
use yii\caching\TagDependency; |
23
|
|
|
use yii\data\ActiveDataProvider; |
24
|
|
|
use yii\db\ActiveQuery; |
25
|
|
|
use yii\db\ActiveRecord; |
26
|
|
|
use yii\db\Expression; |
27
|
|
|
use yii\db\Query; |
28
|
|
|
use yii\helpers\ArrayHelper; |
29
|
|
|
use yii\data\Pagination; |
30
|
|
|
use yii\web\ServerErrorHttpException; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* This is the model class for table "product". |
34
|
|
|
* |
35
|
|
|
* @property integer $id |
36
|
|
|
* @property integer $main_category_id |
37
|
|
|
* @property string $name |
38
|
|
|
* @property string $title |
39
|
|
|
* @property string $h1 |
40
|
|
|
* @property string $meta_description |
41
|
|
|
* @property string $breadcrumbs_label |
42
|
|
|
* @property string $slug |
43
|
|
|
* @property string $slug_compiled |
44
|
|
|
* @property integer $slug_absolute |
45
|
|
|
* @property string $content |
46
|
|
|
* @property string $announce |
47
|
|
|
* @property integer $sort_order |
48
|
|
|
* @property integer $active |
49
|
|
|
* @property double $price |
50
|
|
|
* @property double $old_price |
51
|
|
|
* @property integer $parent_id |
52
|
|
|
* @property integer $currency_id |
53
|
|
|
* @property integer $measure_id |
54
|
|
|
* @property Product[] $relatedProducts |
55
|
|
|
* @property Measure $measure |
56
|
|
|
* @property string $sku |
57
|
|
|
* @property boolean $unlimited_count |
58
|
|
|
* @property string $date_added |
59
|
|
|
* @property string $date_modified |
60
|
|
|
* Relations: |
61
|
|
|
* @property Category $category |
62
|
|
|
* @property Product[] $children |
63
|
|
|
* @property Category $mainCategory |
64
|
|
|
*/ |
65
|
|
|
|
66
|
|
|
class Product extends ActiveRecord implements ImportableInterface, ExportableInterface, \JsonSerializable |
67
|
|
|
{ |
68
|
|
|
use GetImages; |
69
|
|
|
use HasAddonTrait; |
70
|
|
|
|
71
|
|
|
protected static $identity_map = []; |
72
|
|
|
protected static $slug_to_id = []; |
73
|
|
|
protected $category_ids = null; |
74
|
|
|
|
75
|
|
|
public $relatedProductsArray = []; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @var null|WarehouseProduct[] Stores warehouses state of product. Use Product::getWarehousesState() to retrieve |
79
|
|
|
*/ |
80
|
|
|
protected $activeWarehousesState = null; |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @inheritdoc |
84
|
|
|
*/ |
85
|
|
|
public static function tableName() |
86
|
|
|
{ |
87
|
|
|
return '{{%product}}'; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @inheritdoc |
92
|
|
|
*/ |
93
|
|
|
public function rules() |
94
|
|
|
{ |
95
|
|
|
return [ |
96
|
|
|
[['sku'], 'filter', 'filter' => ['\app\backend\components\Helper', 'toString']], |
97
|
|
|
[['main_category_id', 'name', 'slug'], 'required'], |
98
|
|
|
[ |
99
|
|
|
[ |
100
|
|
|
'main_category_id', |
101
|
|
|
'slug_absolute', |
102
|
|
|
'sort_order', |
103
|
|
|
'parent_id', |
104
|
|
|
'currency_id', |
105
|
|
|
], |
106
|
|
|
'integer' |
107
|
|
|
], |
108
|
|
|
[ |
109
|
|
|
[ |
110
|
|
|
'name', |
111
|
|
|
'title', |
112
|
|
|
'h1', |
113
|
|
|
'meta_description', |
114
|
|
|
'breadcrumbs_label', |
115
|
|
|
'content', |
116
|
|
|
'announce', |
117
|
|
|
'option_generate', |
118
|
|
|
'sku' |
119
|
|
|
], |
120
|
|
|
'string' |
121
|
|
|
], |
122
|
|
|
[ |
123
|
|
|
[ |
124
|
|
|
'unlimited_count', |
125
|
|
|
'active', |
126
|
|
|
'slug_absolute', |
127
|
|
|
], |
128
|
|
|
'boolean', |
129
|
|
|
], |
130
|
|
|
[['price', 'old_price'], 'number'], |
131
|
|
|
[['slug'], 'string', 'max' => 80], |
132
|
|
|
[['slug_compiled'], 'string', 'max' => 180], |
133
|
|
|
[['old_price', 'price',], 'default', 'value' => 0,], |
134
|
|
|
[['active', 'unlimited_count'], 'default', 'value' => true], |
135
|
|
|
[['parent_id', 'slug_absolute', 'sort_order'], 'default', 'value' => 0], |
136
|
|
|
[['sku', 'name'], 'default', 'value' => ''], |
137
|
|
|
[['unlimited_count', 'currency_id', 'measure_id'], 'default', 'value' => 1], |
138
|
|
|
[['relatedProductsArray'], 'safe'], |
139
|
|
|
[['slug'], 'unique', 'targetAttribute' => ['slug', 'main_category_id']], |
140
|
|
|
[['date_added', 'date_modified'], 'safe'], |
141
|
|
|
|
142
|
|
|
]; |
143
|
|
|
} |
144
|
|
|
/** |
145
|
|
|
* @inheritdoc |
146
|
|
|
*/ |
147
|
|
|
public function attributeLabels() |
148
|
|
|
{ |
149
|
|
|
return [ |
150
|
|
|
'id' => Yii::t('app', 'ID'), |
151
|
|
|
'main_category_id' => Yii::t('app', 'Main Category ID'), |
152
|
|
|
'parent_id' => Yii::t('app', 'Parent ID'), |
153
|
|
|
'name' => Yii::t('app', 'Name'), |
154
|
|
|
'title' => Yii::t('app', 'Title'), |
155
|
|
|
'h1' => Yii::t('app', 'H1'), |
156
|
|
|
'meta_description' => Yii::t('app', 'Meta Description'), |
157
|
|
|
'breadcrumbs_label' => Yii::t('app', 'Breadcrumbs Label'), |
158
|
|
|
'slug' => Yii::t('app', 'Slug'), |
159
|
|
|
'slug_compiled' => Yii::t('app', 'Slug Compiled'), |
160
|
|
|
'slug_absolute' => Yii::t('app', 'Slug Absolute'), |
161
|
|
|
'content' => Yii::t('app', 'Content'), |
162
|
|
|
'announce' => Yii::t('app', 'Announce'), |
163
|
|
|
'sort_order' => Yii::t('app', 'Sort Order'), |
164
|
|
|
'active' => Yii::t('app', 'Active'), |
165
|
|
|
'price' => Yii::t('app', 'Price'), |
166
|
|
|
'old_price' => Yii::t('app', 'Old Price'), |
167
|
|
|
'option_generate' => Yii::t('app', 'Option Generate'), |
168
|
|
|
'in_warehouse' => Yii::t('app', 'Items in warehouse'), |
169
|
|
|
'sku' => Yii::t('app', 'SKU'), |
170
|
|
|
'unlimited_count' => Yii::t('app', 'Unlimited items(don\'t count in warehouse)'), |
171
|
|
|
'reserved_count' => Yii::t('app', 'Items reserved'), |
172
|
|
|
'relatedProductsArray' => Yii::t('app', 'Related products'), |
173
|
|
|
'currency_id' => Yii::t('app', 'Currency'), |
174
|
|
|
'measure_id' => Yii::t('app', 'Measure'), |
175
|
|
|
'date_added' => Yii::t('app', 'Date Added'), |
176
|
|
|
'date_modified' => Yii::t('app', 'Date Modified'), |
177
|
|
|
]; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* @inheritdoc |
182
|
|
|
*/ |
183
|
|
View Code Duplication |
public function behaviors() |
184
|
|
|
{ |
185
|
|
|
return [ |
186
|
|
|
[ |
187
|
|
|
'class' => Tree::className(), |
|
|
|
|
188
|
|
|
'activeAttribute' => 'active', |
189
|
|
|
'sortOrder' => [ |
190
|
|
|
'sort_order' => SORT_ASC, |
191
|
|
|
'id' => SORT_ASC |
192
|
|
|
], |
193
|
|
|
], |
194
|
|
|
[ |
195
|
|
|
'class' => HasProperties::className(), |
|
|
|
|
196
|
|
|
], |
197
|
|
|
[ |
198
|
|
|
'class' => ActiveRecordHelper::className(), |
|
|
|
|
199
|
|
|
], |
200
|
|
|
[ |
201
|
|
|
'class' => CleanRelations::className(), |
|
|
|
|
202
|
|
|
], |
203
|
|
|
[ |
204
|
|
|
'class' => TimestampBehavior::className(), |
|
|
|
|
205
|
|
|
'createdAtAttribute' => 'date_added', |
206
|
|
|
'updatedAtAttribute' => 'date_modified', |
207
|
|
|
'value' => new Expression('NOW()'), |
208
|
|
|
'attributes' => [ |
209
|
|
|
ActiveRecord::EVENT_BEFORE_INSERT => ['date_added'], |
210
|
|
|
ActiveRecord::EVENT_BEFORE_UPDATE => ['date_modified'], |
211
|
|
|
], |
212
|
|
|
], |
213
|
|
|
]; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Search products |
218
|
|
|
* @param $params |
219
|
|
|
* @return ActiveDataProvider |
220
|
|
|
*/ |
221
|
|
|
public function search($params) |
222
|
|
|
{ |
223
|
|
|
$product = Yii::$container->get(Product::class); |
224
|
|
|
/* @var $query \yii\db\ActiveQuery */ |
225
|
|
|
$query = $product::find()->where(['parent_id' => 0])->with('images'); |
226
|
|
|
$dataProvider = new ActiveDataProvider( |
227
|
|
|
[ |
228
|
|
|
'query' => $query, |
229
|
|
|
'pagination' => [ |
230
|
|
|
'pageSize' => 10, |
231
|
|
|
], |
232
|
|
|
] |
233
|
|
|
); |
234
|
|
|
if (!($this->load($params))) { |
235
|
|
|
return $dataProvider; |
236
|
|
|
} |
237
|
|
|
$query->andFilterWhere(['id' => $this->id]); |
238
|
|
|
$query->andFilterWhere(['like', 'name', $this->name]); |
239
|
|
|
$query->andFilterWhere(['like', 'slug', $this->slug]); |
240
|
|
|
$query->andFilterWhere(['active' => $this->active]); |
241
|
|
|
$query->andFilterWhere(['price' => $this->price]); |
242
|
|
|
$query->andFilterWhere(['old_price' => $this->old_price]); |
243
|
|
|
$query->andFilterWhere(['like', 'sku', $this->sku]); |
244
|
|
|
return $dataProvider; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* Returns model instance by ID using per-request Identity Map and cache |
249
|
|
|
* @param $id |
250
|
|
|
* @param int $isActive Return only active |
251
|
|
|
* @return Product |
252
|
|
|
*/ |
253
|
|
View Code Duplication |
public static function findById($id, $isActive = 1) |
254
|
|
|
{ |
255
|
|
|
if (!is_numeric($id)) { |
256
|
|
|
return null; |
257
|
|
|
} |
258
|
|
|
if (!isset(static::$identity_map[$id])) { |
259
|
|
|
$cacheKey = static::tableName() . ":$id:$isActive"; |
260
|
|
|
if (false === $model = Yii::$app->cache->get($cacheKey)) { |
261
|
|
|
$model = static::find()->where(['id' => $id])->with('images'); |
262
|
|
|
if (null !== $isActive) { |
263
|
|
|
$model->andWhere(['active' => $isActive]); |
264
|
|
|
} |
265
|
|
|
if (null !== $model = $model->one()) { |
266
|
|
|
/** |
267
|
|
|
* @var self $model |
268
|
|
|
*/ |
269
|
|
|
static::$slug_to_id[$model->slug] = $id; |
270
|
|
|
Yii::$app->cache->set( |
271
|
|
|
$cacheKey, |
272
|
|
|
$model, |
273
|
|
|
86400, |
274
|
|
|
new TagDependency( |
275
|
|
|
[ |
276
|
|
|
'tags' => [ |
277
|
|
|
ActiveRecordHelper::getCommonTag(static::className()) |
|
|
|
|
278
|
|
|
] |
279
|
|
|
] |
280
|
|
|
) |
281
|
|
|
); |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
static::$identity_map[$id] = $model; |
285
|
|
|
} |
286
|
|
|
return static::$identity_map[$id]; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Find a product by slug |
291
|
|
|
* @param string $slug |
292
|
|
|
* @param int $inCategoryId |
|
|
|
|
293
|
|
|
* @param int $isActive |
294
|
|
|
* @return Product |
295
|
|
|
*/ |
296
|
|
|
public static function findBySlug($slug, $inCategoryId = null, $isActive = 1) |
297
|
|
|
{ |
298
|
|
|
if (!isset(static::$slug_to_id[$slug])) { |
299
|
|
|
$cacheKey = static::tableName() . "$slug:$inCategoryId"; |
300
|
|
|
if (false === $model = Yii::$app->cache->get($cacheKey)) { |
301
|
|
|
$tags = []; |
302
|
|
|
/** @var ActiveQuery $model */ |
303
|
|
|
$query = static::find()->where( |
304
|
|
|
[ |
305
|
|
|
'slug' => $slug, |
306
|
|
|
'active' => $isActive, |
307
|
|
|
] |
308
|
|
|
)->with('images', 'relatedProducts'); |
309
|
|
|
if (!is_null($inCategoryId)) { |
310
|
|
|
$query->andWhere(['main_category_id' => $inCategoryId]); |
311
|
|
|
$tags[] = ActiveRecordHelper::getObjectTag(Category::className(), $inCategoryId); |
|
|
|
|
312
|
|
|
} |
313
|
|
|
$model = $query->one(); |
314
|
|
|
$product = Yii::$container->get(Product::class); |
315
|
|
|
/** |
316
|
|
|
* @var self|null $model |
317
|
|
|
*/ |
318
|
|
|
if (is_null($model)) { |
319
|
|
|
$tags[] = ActiveRecordHelper::getCommonTag(get_class($product)); |
320
|
|
|
} else { |
321
|
|
|
$tags[] = ActiveRecordHelper::getObjectTag(get_class($product), $model->id); |
322
|
|
|
} |
323
|
|
|
Yii::$app->cache->set( |
324
|
|
|
$cacheKey, |
325
|
|
|
$model, |
326
|
|
|
86400, |
327
|
|
|
new TagDependency([ |
328
|
|
|
'tags' => $tags, |
329
|
|
|
]) |
330
|
|
|
); |
331
|
|
|
} |
332
|
|
|
if (is_object($model)) { |
333
|
|
|
static::$identity_map[$model->id] = $model; |
334
|
|
|
static::$slug_to_id[$slug] = $model->id; |
335
|
|
|
return $model; |
336
|
|
|
} |
337
|
|
|
return null; |
338
|
|
|
} else { |
339
|
|
|
if (isset(static::$identity_map[static::$slug_to_id[$slug]])) { |
340
|
|
|
return static::$identity_map[static::$slug_to_id[$slug]]; |
341
|
|
|
} |
342
|
|
|
return static::findById(static::$slug_to_id[$slug]); |
343
|
|
|
} |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* @return Category|null |
|
|
|
|
348
|
|
|
*/ |
349
|
|
|
public function getCategory() |
350
|
|
|
{ |
351
|
|
|
return $this->hasOne(Category::className(), ['id' => 'main_category_id']); |
|
|
|
|
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
public function getOptions() |
355
|
|
|
{ |
356
|
|
|
return $this->hasMany(static::className(), ['parent_id' => 'id']); |
|
|
|
|
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
public function getCurrency() |
360
|
|
|
{ |
361
|
|
|
return $this->hasOne(Currency::className(), ['id' => 'currency_id']); |
|
|
|
|
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* @return ActiveQuery |
366
|
|
|
*/ |
367
|
|
|
public function getRelatedProducts() |
368
|
|
|
{ |
369
|
|
|
$product = Yii::$container->get(Product::class); |
370
|
|
|
return $this->hasMany(get_class($product), ['id' => 'related_product_id']) |
371
|
|
|
->viaTable( |
372
|
|
|
RelatedProduct::tableName(), |
373
|
|
|
['product_id' => 'id'], |
374
|
|
|
function($relation) { |
375
|
|
|
/** @var \yii\db\ActiveQuery $relation */ |
376
|
|
|
return $relation->orderBy('sort_order ASC'); |
377
|
|
|
} |
378
|
|
|
) |
379
|
|
|
->innerJoin('{{%related_product}}','related_product.product_id=:id AND related_product.related_product_id =product.id',[':id'=>$this->id]) |
380
|
|
|
->orderBy('related_product.sort_order ASC') |
381
|
|
|
->andWhere(["active" => 1]); |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
public function getImage() |
385
|
|
|
{ |
386
|
|
|
$result = $this->hasOne(Image::className(), ['object_model_id' => 'id']); |
|
|
|
|
387
|
|
|
$object = BaseObject::getForClass($this->className()); |
|
|
|
|
388
|
|
|
return $result->andWhere(['object_id' => $object->id]); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Returns remains of this product in all active warehouses. |
394
|
|
|
* Note that if warehouse was added after product edit - it will not be shown here. |
395
|
|
|
* @return WarehouseProduct[] |
396
|
|
|
*/ |
397
|
|
|
public function getWarehousesState() |
398
|
|
|
{ |
399
|
|
|
if ($this->activeWarehousesState === null) { |
400
|
|
|
$this->activeWarehousesState = WarehouseProduct::getDb()->cache( |
401
|
|
|
function($db) { |
|
|
|
|
402
|
|
|
return WarehouseProduct::find() |
403
|
|
|
->where(['in', 'warehouse_id', Warehouse::activeWarehousesIds()]) |
404
|
|
|
->andWhere('product_id=:product_id', [':product_id'=>$this->id]) |
405
|
|
|
->with('warehouse') |
406
|
|
|
->all(); |
407
|
|
|
}, |
408
|
|
|
86400, |
409
|
|
|
new TagDependency( |
410
|
|
|
[ |
411
|
|
|
'tags' => [ |
412
|
|
|
ActiveRecordHelper::getObjectTag($this->className(), $this->id), |
|
|
|
|
413
|
|
|
] |
414
|
|
|
] |
415
|
|
|
) |
416
|
|
|
); |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
return $this->activeWarehousesState; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
public function beforeSave($insert) |
423
|
|
|
{ |
424
|
|
|
if (empty($this->breadcrumbs_label)) { |
425
|
|
|
$this->breadcrumbs_label = $this->name; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
if (empty($this->h1)) { |
429
|
|
|
$this->h1 = $this->name; |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
if (empty($this->title)) { |
433
|
|
|
$this->title = $this->name; |
434
|
|
|
} |
435
|
|
|
$object = BaseObject::getForClass(static::className()); |
|
|
|
|
436
|
|
|
|
437
|
|
|
TagDependency::invalidate( |
438
|
|
|
Yii::$app->cache, |
439
|
|
|
[ |
440
|
|
|
'Images:' . $object->id . ':' . $this->id |
441
|
|
|
] |
442
|
|
|
); |
443
|
|
|
|
444
|
|
|
return parent::beforeSave($insert); |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* @inheritdoc |
449
|
|
|
*/ |
450
|
|
|
public function afterSave($insert, $changedAttributes) |
451
|
|
|
{ |
452
|
|
|
parent::afterSave($insert, $changedAttributes); |
453
|
|
|
/** |
454
|
|
|
* @todo Implement a good decision instead of this. |
455
|
|
|
* It resolves a problem with Import (We keep data but do not use it. It produce a memory leak). |
456
|
|
|
* Another decision is do not save data if it does not exist (if (isset(static::$identity_map[$this->id]) === true) {static::$identity_map[$this->id] = $this;}). |
457
|
|
|
* Both decisions is not good. We think about it all day and all night but have no result. You may offer a true way :) |
458
|
|
|
*/ |
459
|
|
|
unset(static::$identity_map[$this->id]); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Preparation to delete product. |
464
|
|
|
* Deleting all inserted products. |
465
|
|
|
* @return bool |
466
|
|
|
*/ |
467
|
|
View Code Duplication |
public function beforeDelete() |
468
|
|
|
{ |
469
|
|
|
if (!parent::beforeDelete()) { |
470
|
|
|
return false; |
471
|
|
|
} |
472
|
|
|
foreach ($this->children as $child) { |
473
|
|
|
$child->delete(); |
474
|
|
|
} |
475
|
|
|
return true; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
public function saveCategoriesBindings(array $categories_ids) |
479
|
|
|
{ |
480
|
|
|
$object = BaseObject::getForClass(static::className()); |
|
|
|
|
481
|
|
|
$catIds = $this->getCategoryIds(); |
482
|
|
|
|
483
|
|
|
$remove = []; |
484
|
|
|
$add = []; |
485
|
|
|
|
486
|
|
|
foreach ($catIds as $catsKey => $value) { |
487
|
|
|
$key = array_search($value, $categories_ids); |
488
|
|
|
if ($key === false) { |
489
|
|
|
$remove[] = $value; |
490
|
|
|
unset($this->category_ids[$catsKey]); |
491
|
|
|
} else { |
492
|
|
|
unset($categories_ids[$key]); |
493
|
|
|
} |
494
|
|
|
} |
495
|
|
|
foreach ($categories_ids as $value) { |
496
|
|
|
$add[] = [ |
497
|
|
|
$value, |
498
|
|
|
$this->id |
499
|
|
|
]; |
500
|
|
|
$this->category_ids[] = $value; |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
Yii::$app->db->createCommand()->delete( |
504
|
|
|
$object->categories_table_name, |
505
|
|
|
['and', 'object_model_id = :id', ['in', 'category_id', $remove]], |
506
|
|
|
[':id' => $this->id] |
507
|
|
|
)->execute(); |
508
|
|
View Code Duplication |
if (!empty($add)) { |
509
|
|
|
Yii::$app->db->createCommand()->batchInsert( |
510
|
|
|
$object->categories_table_name, |
511
|
|
|
['category_id', 'object_model_id'], |
512
|
|
|
$add |
513
|
|
|
)->execute(); |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
|
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
/** |
520
|
|
|
* @return array |
521
|
|
|
*/ |
522
|
|
|
public function getCategoryIds() |
523
|
|
|
{ |
524
|
|
|
if ($this->category_ids === null) { |
525
|
|
|
$object = BaseObject::getForClass(static::className()); |
|
|
|
|
526
|
|
|
$this->category_ids = (new Query())->select('category_id')->from([$object->categories_table_name])->where( |
527
|
|
|
'object_model_id = :id', |
528
|
|
|
[':id' => $this->id] |
529
|
|
|
)->orderBy(['sort_order' => SORT_ASC, 'id' => SORT_ASC])->column(); |
530
|
|
|
} |
531
|
|
|
return $this->category_ids; |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Process fields before the actual model is saved(inserted or updated) |
536
|
|
|
* @param array $fields |
537
|
|
|
* @param $multipleValuesDelimiter |
538
|
|
|
* @param array $additionalFields |
539
|
|
|
*/ |
540
|
|
|
public function processImportBeforeSave(array $fields, $multipleValuesDelimiter, array $additionalFields) |
541
|
|
|
{ |
542
|
|
|
$_attributes = $this->attributes(); |
543
|
|
|
foreach ($fields as $key => $value) { |
544
|
|
|
if (in_array($key, $_attributes)) { |
545
|
|
|
$this->$key = $value; |
546
|
|
|
} |
547
|
|
|
} |
548
|
|
|
|
549
|
|
|
$categories = $this->unpackCategories($fields, $multipleValuesDelimiter, $additionalFields); |
550
|
|
|
if ($categories !== false && $this->main_category_id < 1) { |
551
|
|
|
if (count($categories) == 0) { |
552
|
|
|
$categories = [1]; |
553
|
|
|
} |
554
|
|
|
$this->main_category_id = $categories[0]; |
555
|
|
|
} |
556
|
|
|
|
557
|
|
View Code Duplication |
if (empty($this->slug)) { |
558
|
|
|
$this->slug = Helper::createSlug($this->name); |
559
|
|
|
} elseif (mb_strlen($this->slug) > 80) { |
560
|
|
|
$this->slug = mb_substr($this->slug, 0, 80); |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
if (empty($this->name)) { |
564
|
|
|
$this->name = 'unnamed-product'; |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
if (!is_numeric($this->price)) { |
568
|
|
|
$this->price = 0; |
569
|
|
|
} |
570
|
|
|
if (!is_numeric($this->old_price)) { |
571
|
|
|
$this->old_price = 0; |
572
|
|
|
} |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
/** |
576
|
|
|
* Process fields after the actual model is saved(inserted or updated) |
577
|
|
|
* @param array $fields |
578
|
|
|
* @param $multipleValuesDelimiter |
579
|
|
|
* @param array $additionalFields |
580
|
|
|
*/ |
581
|
|
|
public function processImportAfterSave(array $fields, $multipleValuesDelimiter, array $additionalFields) |
582
|
|
|
{ |
583
|
|
|
$categories = $this->unpackCategories($fields, $multipleValuesDelimiter, $additionalFields); |
584
|
|
|
|
585
|
|
|
if ($categories === false) { |
586
|
|
|
$categories = [$this->main_category_id]; |
587
|
|
|
} |
588
|
|
|
$this->saveCategoriesBindings($categories); |
|
|
|
|
589
|
|
|
|
590
|
|
|
|
591
|
|
|
$images = isset($fields['images']) ? $fields['images'] : (isset($fields['image']) ? $fields['image'] : false); |
592
|
|
|
if ($images !== false) { |
593
|
|
View Code Duplication |
if (strpos($images, $multipleValuesDelimiter) > 0) { |
594
|
|
|
$images = explode($multipleValuesDelimiter, $images); |
595
|
|
|
} elseif (strpos($multipleValuesDelimiter, '/') === 0) { |
596
|
|
|
$images = preg_split($multipleValuesDelimiter, $images); |
597
|
|
|
} else { |
598
|
|
|
$images = [$images]; |
599
|
|
|
} |
600
|
|
|
$input_array = []; |
601
|
|
|
foreach ($images as $image_src) { |
602
|
|
|
$input_array[] = [ |
603
|
|
|
'filename' => $image_src, |
604
|
|
|
]; |
605
|
|
|
} |
606
|
|
|
if (count($input_array) > 0) { |
607
|
|
|
Image::replaceForModel($this, $input_array); |
608
|
|
|
} |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
if (isset($additionalFields['relatedProducts'])) { |
612
|
|
|
if (isset($additionalFields['relatedProducts']['processValuesAs'],$fields['relatedProducts'])) { |
613
|
|
|
|
614
|
|
|
$ids = explode($multipleValuesDelimiter, $fields['relatedProducts']); |
615
|
|
|
$this->relatedProductsArray=$ids; |
616
|
|
|
$this->saveRelatedProducts(); |
617
|
|
|
} |
618
|
|
|
} |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* Makes an array of category ids from string |
623
|
|
|
* |
624
|
|
|
* @param array $fields |
625
|
|
|
* @param $multipleValuesDelimiter |
626
|
|
|
* @param array $additionalFields |
627
|
|
|
* @return array|bool |
628
|
|
|
*/ |
629
|
|
|
protected function unpackCategories(array $fields, $multipleValuesDelimiter, array $additionalFields) |
630
|
|
|
{ |
631
|
|
|
$categories = isset($fields['categories']) ? $fields['categories'] : (isset($fields['category']) ? $fields['category'] : false); |
632
|
|
|
if ($categories === false || empty($fields['categories'])) { |
633
|
|
|
return $this->getCategoryIds(); |
634
|
|
|
|
635
|
|
|
} |
636
|
|
|
if ($categories !== false) { |
637
|
|
View Code Duplication |
if (strpos($categories, $multipleValuesDelimiter) > 0) { |
638
|
|
|
$categories = explode($multipleValuesDelimiter, $categories); |
639
|
|
|
} elseif (strpos($multipleValuesDelimiter, '/') === 0) { |
640
|
|
|
$categories = preg_split($multipleValuesDelimiter, $categories); |
641
|
|
|
} else { |
642
|
|
|
$categories = [$categories]; |
643
|
|
|
} |
644
|
|
|
$typecast = 'id'; |
645
|
|
|
|
646
|
|
|
if (isset($additionalFields['categories'])) { |
647
|
|
|
if (isset($additionalFields['categories']['processValuesAs'])) { |
648
|
|
|
$typecast = $additionalFields['categories']['processValuesAs']; |
649
|
|
|
} |
650
|
|
|
} |
651
|
|
|
if ($typecast === 'id') { |
652
|
|
|
$categories = array_map('intval', $categories); |
653
|
|
|
} elseif ($typecast === 'slug') { |
654
|
|
|
$categories = array_map('trim', $categories); |
655
|
|
|
$categoryIds = []; |
656
|
|
View Code Duplication |
foreach ($categories as $part) { |
657
|
|
|
$cat = Category::findBySlug($part, 1, -1); |
658
|
|
|
if (is_object($cat)) { |
659
|
|
|
$categoryIds[] = $cat->id; |
660
|
|
|
} |
661
|
|
|
unset($cat); |
662
|
|
|
} |
663
|
|
|
$categories = array_map('intval', $categoryIds); |
664
|
|
|
} elseif ($typecast === 'name') { |
665
|
|
|
$categories = array_map('trim', $categories); |
666
|
|
|
$categoryIds = []; |
667
|
|
View Code Duplication |
foreach ($categories as $part) { |
668
|
|
|
$cat = Category::findByName($part, 1, -1); |
669
|
|
|
if (is_object($cat)) { |
670
|
|
|
$categoryIds[] = $cat->id; |
671
|
|
|
} |
672
|
|
|
unset($cat); |
673
|
|
|
} |
674
|
|
|
$categories = array_map('intval', $categoryIds); |
675
|
|
|
} else { |
676
|
|
|
// that's unusual behavior |
677
|
|
|
$categories = false; |
678
|
|
|
} |
679
|
|
|
|
680
|
|
|
// post-process categories |
681
|
|
|
// find & add parent category |
682
|
|
|
// if we need to show products of child categories in products list |
683
|
|
|
/** @var ShopModule $module */ |
684
|
|
|
$module = Yii::$app->getModule('shop'); |
685
|
|
|
if (is_array($categories) && $module->showProductsOfChildCategories) { |
686
|
|
|
do { |
687
|
|
|
$repeat = false; |
688
|
|
|
foreach ($categories as $cat) { |
689
|
|
|
$model = Category::findById($cat, null, null); |
690
|
|
|
if ($model === null) { |
691
|
|
|
echo "\n\nUnknown category with id ".intval($cat) ." for model with id:".$this->id."\n\n"; |
692
|
|
|
continue; |
693
|
|
|
} |
694
|
|
|
if (intval($model->parent_id) > 0 && in_array($model->parent_id, $categories) === false) { |
695
|
|
|
$categories[] = $model->parent_id; |
696
|
|
|
$repeat = true; |
697
|
|
|
} |
698
|
|
|
|
699
|
|
|
unset($model); |
700
|
|
|
} |
701
|
|
|
} while ($repeat === true); |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
} |
705
|
|
|
return $categories; |
706
|
|
|
} |
707
|
|
|
|
708
|
|
|
/** |
709
|
|
|
* Additional fields with labels. |
710
|
|
|
* Translation should be implemented internally in this function. |
711
|
|
|
* For now will be rendered as checkbox list with label. |
712
|
|
|
* Note: properties should not be in the result - they are served other way. |
713
|
|
|
* Format: |
714
|
|
|
* [ |
715
|
|
|
* 'field_key' => 'Your awesome translated field title', |
716
|
|
|
* 'another' => 'Another field label', |
717
|
|
|
* ] |
718
|
|
|
* @return array |
|
|
|
|
719
|
|
|
*/ |
720
|
|
|
public static function exportableAdditionalFields() |
721
|
|
|
{ |
722
|
|
|
return [ |
723
|
|
|
'categories' => [ |
724
|
|
|
'label' => Yii::t('app', 'Categories'), |
725
|
|
|
'processValueAs' => [ |
726
|
|
|
'id' => Yii::t('app', 'ID'), |
727
|
|
|
'name' => Yii::t('app', 'Name'), |
728
|
|
|
'slug' => Yii::t('app', 'Slug'), |
729
|
|
|
] |
730
|
|
|
], |
731
|
|
|
'images' => [ |
732
|
|
|
'label' => Yii::t('app', 'Images'), |
733
|
|
|
'processValueAs' => [ |
734
|
|
|
'filename' => Yii::t('app', 'Filename'), |
735
|
|
|
'id' => Yii::t('app', 'ID'), |
736
|
|
|
] |
737
|
|
|
], |
738
|
|
|
'relatedProducts' => [ |
739
|
|
|
'label' => Yii::t('app', 'Related products'), |
740
|
|
|
'processValueAs' => [ |
741
|
|
|
'id' => Yii::t('app', 'ID'), |
742
|
|
|
], |
743
|
|
|
], |
744
|
|
|
]; |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
/** |
748
|
|
|
* Returns additional fields data by field key. |
749
|
|
|
* If value of field is array it will be converted to string |
750
|
|
|
* using multipleValuesDelimiter specified in ImportModel |
751
|
|
|
* @param array $configuration |
752
|
|
|
* @return array |
753
|
|
|
*/ |
754
|
|
|
public function getAdditionalFields(array $configuration) |
755
|
|
|
{ |
756
|
|
|
$result = []; |
757
|
|
|
|
758
|
|
|
if (isset($configuration['categories'], $configuration['categories']['processValuesAs']) |
759
|
|
|
&& $configuration['categories']['enabled'] |
760
|
|
|
) { |
761
|
|
|
if ($configuration['categories']['processValuesAs'] === 'id') { |
762
|
|
|
$result['categories'] = $this->getCategoryIds(); |
763
|
|
|
} else { |
764
|
|
|
$ids = $this->getCategoryIds(); |
765
|
|
|
$result['categories'] = []; |
766
|
|
|
|
767
|
|
|
foreach ($ids as $id) { |
768
|
|
|
$category = Category::findById($id, null, null); |
769
|
|
|
if ($category) { |
770
|
|
|
$result['categories'][] = $category->getAttribute( |
771
|
|
|
$configuration['categories']['processValuesAs'] |
772
|
|
|
); |
773
|
|
|
} |
774
|
|
|
unset($category); |
775
|
|
|
} |
776
|
|
|
} |
777
|
|
|
} |
778
|
|
|
if (isset($configuration['images'], $configuration['images']['processValuesAs']) |
779
|
|
|
&& $configuration['images']['enabled'] |
780
|
|
|
) { |
781
|
|
|
$object = BaseObject::getForClass($this->className()); |
|
|
|
|
782
|
|
|
$images = Image::getForModel($object->id, $this->id); |
783
|
|
|
$result['images'] = ArrayHelper::getColumn($images, $configuration['images']['processValuesAs']); |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
if (isset($configuration['relatedProducts'], $configuration['relatedProducts']['processValuesAs']) |
787
|
|
|
&& $configuration['relatedProducts']['enabled'] |
788
|
|
|
) { |
789
|
|
|
$result['relatedProducts'] = ArrayHelper::getColumn($this->relatedProducts, $configuration['relatedProducts']['processValuesAs']); |
790
|
|
|
} |
791
|
|
|
|
792
|
|
|
|
793
|
|
|
return $result; |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
/** |
797
|
|
|
* Returns products for special filtration query |
798
|
|
|
* Used in ProductsWidget and ProductController |
799
|
|
|
* |
800
|
|
|
* @param $category_group_id |
801
|
|
|
* @param array $values_by_property_id |
802
|
|
|
* @param null|integer|string $selected_category_id |
803
|
|
|
* @param bool|string $force_sorting If false - use UserPreferences, if string - use supplied orderBy condition |
804
|
|
|
* @param null|integer $limit limit query results |
805
|
|
|
* @param bool $apply_filterquery Should we apply filter query(filters based on query params ie. price_min/max) |
806
|
|
|
* @param bool $force_limit False to use Pagination, true to use $limit and ignore pagination |
807
|
|
|
* @param array $additional_filters Array of callables that will apply additional filters to query |
808
|
|
|
* @return array |
809
|
|
|
* @throws ServerErrorHttpException |
810
|
|
|
* @throws \Exception |
811
|
|
|
*/ |
812
|
|
|
public static function filteredProducts( |
813
|
|
|
$category_group_id, |
814
|
|
|
array $values_by_property_id = [], |
815
|
|
|
$selected_category_id = null, |
816
|
|
|
$force_sorting = false, |
817
|
|
|
$limit = null, |
818
|
|
|
$apply_filterquery = true, |
819
|
|
|
$force_limit = false, |
820
|
|
|
array $additional_filters = [] |
821
|
|
|
) { |
822
|
|
|
Yii::beginProfile("FilteredProducts"); |
823
|
|
|
/** @var \app\models\BaseObject $object */ |
824
|
|
|
if (null === $object = BaseObject::getForClass(static::className())) { |
|
|
|
|
825
|
|
|
throw new ServerErrorHttpException('Object not found.'); |
826
|
|
|
} |
827
|
|
|
|
828
|
|
|
/** @var \app\modules\shop\ShopModule $module */ |
829
|
|
|
$module = Yii::$app->getModule('shop'); |
830
|
|
|
|
831
|
|
|
|
832
|
|
|
$query = static::find()->with('images'); |
833
|
|
|
if ($module->productsFilteringMode === ConfigConfigurationModel::FILTER_PARENTS_ONLY) { |
834
|
|
|
$query->andWhere([static::tableName() . '.parent_id' => 0]); |
835
|
|
|
} elseif ($module->productsFilteringMode === ConfigConfigurationModel::FILTER_CHILDREN_ONLY) { |
836
|
|
|
$query->andWhere(['!=', static::tableName() . '.parent_id', 0]); |
837
|
|
|
} |
838
|
|
|
$query->andWhere([static::tableName() . '.active' => 1]); |
839
|
|
|
|
840
|
|
|
|
841
|
|
|
if (null !== $selected_category_id) { |
842
|
|
|
$query->innerJoin( |
843
|
|
|
$object->categories_table_name . ' ocats', |
844
|
|
|
'ocats.category_id = :catid AND ocats.object_model_id = ' . static::tableName() . '.id', |
845
|
|
|
[':catid' => $selected_category_id] |
846
|
|
|
); |
847
|
|
|
} else { |
848
|
|
|
$query->innerJoin( |
849
|
|
|
$object->categories_table_name . ' ocats', |
850
|
|
|
'ocats.object_model_id = ' . static::tableName() . '.id' |
851
|
|
|
); |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
$query->innerJoin( |
855
|
|
|
Category::tableName() . ' ocatt', |
856
|
|
|
'ocatt.id = ocats.category_id AND ocatt.category_group_id = :gcatid AND ocatt.active = 1', |
857
|
|
|
[':gcatid' => $category_group_id] |
858
|
|
|
); |
859
|
|
|
$query->addGroupBy(static::tableName() . ".id"); |
860
|
|
|
|
861
|
|
|
|
862
|
|
|
$userSelectedSortingId = UserPreferences::preferences()->getAttributes()['productListingSortId']; |
863
|
|
|
$allSorts = []; |
864
|
|
|
if ($force_sorting === false) { |
865
|
|
|
$allSorts = ProductListingSort::enabledSorts(); |
866
|
|
|
if (isset($allSorts[$userSelectedSortingId])) { |
867
|
|
|
if ($allSorts[$userSelectedSortingId]['sort_field'] == 'product.price') { |
868
|
|
|
$query->leftJoin(Currency::tableName() . ' currency_order ON currency_order.id = product.currency_id'); |
869
|
|
|
$query->addOrderBy( |
870
|
|
|
'product.`price`*currency_order.`convert_rate`' . ' ' |
871
|
|
|
. $allSorts[$userSelectedSortingId]['asc_desc'] |
872
|
|
|
); |
873
|
|
|
} else { |
874
|
|
|
$query->addOrderBy( |
875
|
|
|
$allSorts[$userSelectedSortingId]['sort_field'] . ' ' |
876
|
|
|
. $allSorts[$userSelectedSortingId]['asc_desc'] |
877
|
|
|
); |
878
|
|
|
} |
879
|
|
|
} else { |
880
|
|
|
$query->addOrderBy(static::tableName() . '.sort_order'); |
881
|
|
|
} |
882
|
|
|
} elseif (empty($force_sorting) === false || is_array($force_sorting) === true) { |
883
|
|
|
$query->addOrderBy($force_sorting); |
884
|
|
|
} |
885
|
|
|
|
886
|
|
|
$productsPerPage = $limit === null ? UserPreferences::preferences()->getAttributes( |
887
|
|
|
)['productsPerPage'] : $limit; |
888
|
|
|
|
889
|
|
|
PropertiesHelper::appendPropertiesFilters( |
890
|
|
|
$object, |
891
|
|
|
$query, |
892
|
|
|
$values_by_property_id, |
893
|
|
|
Yii::$app->request->get('p', []), |
894
|
|
|
$module->multiFilterMode |
895
|
|
|
); |
896
|
|
|
|
897
|
|
|
|
898
|
|
|
// apply additional filters |
899
|
|
|
$cacheKeyAppend = ""; |
900
|
|
|
if ($apply_filterquery) { |
901
|
|
|
$query = Yii::$app->filterquery->filter($query, $cacheKeyAppend); |
902
|
|
|
} |
903
|
|
|
|
904
|
|
|
foreach ($additional_filters as $filter) { |
905
|
|
|
if (is_callable($filter)) { |
906
|
|
|
call_user_func_array( |
907
|
|
|
$filter, |
908
|
|
|
[ |
909
|
|
|
&$query, |
910
|
|
|
&$cacheKeyAppend |
911
|
|
|
] |
912
|
|
|
); |
913
|
|
|
} |
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
$cacheKey = 'ProductsCount:' . implode( |
917
|
|
|
'_', |
918
|
|
|
[ |
919
|
|
|
md5($query->createCommand()->getRawSql()), |
920
|
|
|
$limit ? '1' : '0', |
921
|
|
|
$force_limit ? '1' : '0', |
922
|
|
|
$productsPerPage |
923
|
|
|
] |
924
|
|
|
) . $cacheKeyAppend; |
925
|
|
|
|
926
|
|
|
|
927
|
|
|
$pages = null; |
928
|
|
|
|
929
|
|
|
if ($force_limit === true) { |
930
|
|
|
$query->limit($limit); |
931
|
|
|
} else { |
932
|
|
|
$products_query = clone $query; |
933
|
|
|
$products_query->limit(null); |
934
|
|
|
|
935
|
|
|
if (false === $pages = Yii::$app->cache->get($cacheKey)) { |
936
|
|
|
$pages = new FilterPagination( |
937
|
|
|
[ |
938
|
|
|
'defaultPageSize' => !is_null($query->limit) ? $query->limit : $productsPerPage, |
939
|
|
|
'pageSizeLimit' => [], |
940
|
|
|
'forcePageParam' => false, |
941
|
|
|
'totalCount' => $products_query->count(), |
942
|
|
|
] |
943
|
|
|
); |
944
|
|
|
|
945
|
|
|
Yii::$app->cache->set( |
946
|
|
|
$cacheKey, |
947
|
|
|
$pages, |
948
|
|
|
86400, |
949
|
|
|
new TagDependency( |
950
|
|
|
[ |
951
|
|
|
'tags' => [ |
952
|
|
|
ActiveRecordHelper::getCommonTag(Category::className()), |
|
|
|
|
953
|
|
|
ActiveRecordHelper::getCommonTag(static::className()), |
|
|
|
|
954
|
|
|
ActiveRecordHelper::getCommonTag($module->className()), |
|
|
|
|
955
|
|
|
] |
956
|
|
|
] |
957
|
|
|
) |
958
|
|
|
); |
959
|
|
|
} |
960
|
|
|
|
961
|
|
|
$query->offset($pages->offset)->limit($pages->limit); |
962
|
|
|
} |
963
|
|
|
|
964
|
|
|
$cacheKey .= '-' . Yii::$app->request->get('page', 1); |
965
|
|
|
|
966
|
|
|
if (false === $products = Yii::$app->cache->get($cacheKey)) { |
967
|
|
|
$products = $query->all(); |
968
|
|
|
Yii::$app->cache->set( |
969
|
|
|
$cacheKey, |
970
|
|
|
$products, |
971
|
|
|
86400, |
972
|
|
|
new TagDependency( |
973
|
|
|
[ |
974
|
|
|
'tags' => [ |
975
|
|
|
ActiveRecordHelper::getCommonTag(Category::className()), |
|
|
|
|
976
|
|
|
ActiveRecordHelper::getCommonTag(static::className()), |
|
|
|
|
977
|
|
|
ActiveRecordHelper::getCommonTag($module->className()), |
|
|
|
|
978
|
|
|
] |
979
|
|
|
] |
980
|
|
|
) |
981
|
|
|
); |
982
|
|
|
} |
983
|
|
|
|
984
|
|
|
Yii::endProfile("FilteredProducts"); |
985
|
|
|
return [ |
986
|
|
|
'products' => $products, |
987
|
|
|
'pages' => $pages, |
988
|
|
|
'allSorts' => $allSorts, |
989
|
|
|
]; |
990
|
|
|
|
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
/** |
994
|
|
|
* Returns product main category model instance using per-request Identity Map |
995
|
|
|
* @return Category|null |
996
|
|
|
*/ |
997
|
|
|
public function getMainCategory() |
998
|
|
|
{ |
999
|
|
|
return Category::findById($this->main_category_id, null); |
1000
|
|
|
} |
1001
|
|
|
|
1002
|
|
|
public function loadRelatedProductsArray() |
1003
|
|
|
{ |
1004
|
|
|
$this->relatedProductsArray = []; |
1005
|
|
|
foreach ($this->relatedProducts as $product) { |
1006
|
|
|
$this->relatedProductsArray[] = $product->id; |
1007
|
|
|
} |
1008
|
|
|
} |
1009
|
|
|
|
1010
|
|
|
public function saveRelatedProducts() |
1011
|
|
|
{ |
1012
|
|
|
if (!is_array($this->relatedProductsArray)) { |
1013
|
|
|
$this->relatedProductsArray = explode(',', $this->relatedProductsArray); |
1014
|
|
|
} |
1015
|
|
|
|
1016
|
|
|
RelatedProduct::deleteAll( |
1017
|
|
|
[ |
1018
|
|
|
'product_id' => $this->id, |
1019
|
|
|
] |
1020
|
|
|
); |
1021
|
|
|
|
1022
|
|
|
foreach ($this->relatedProductsArray as $index => $relatedProductId) { |
1023
|
|
|
$relation = new RelatedProduct; |
1024
|
|
|
$relation->attributes = [ |
1025
|
|
|
'product_id' => $this->id, |
1026
|
|
|
'related_product_id' => $relatedProductId, |
1027
|
|
|
'sort_order' => $index, |
1028
|
|
|
]; |
1029
|
|
|
$relation->save(); |
1030
|
|
|
} |
1031
|
|
|
} |
1032
|
|
|
|
1033
|
|
|
/** |
1034
|
|
|
* Returns product price(old old_price) converted to $currency. If currency is not set(null) will be converted to main currency |
1035
|
|
|
* @param null|Currency $currency Currency to use in conversion, null for main shop currency |
1036
|
|
|
* @param bool $oldPrice True if you want to return Old Price instead of price |
1037
|
|
|
* @return float |
1038
|
|
|
*/ |
1039
|
|
|
public function convertedPrice($currency = null, $oldPrice = false) |
1040
|
|
|
{ |
1041
|
|
|
if ($currency === null) { |
1042
|
|
|
$currency = Currency::getMainCurrency(); |
1043
|
|
|
} |
1044
|
|
|
$price = $oldPrice === true ? $this->old_price : $this->price; |
1045
|
|
|
|
1046
|
|
|
if ($this->currency_id !== $currency->id) { |
1047
|
|
|
// we need to convert! |
1048
|
|
|
$foreignCurrency = Currency::findById($this->currency_id); |
1049
|
|
|
return round($price / $foreignCurrency->convert_nominal * $foreignCurrency->convert_rate, 2); |
1050
|
|
|
} |
1051
|
|
|
return $price; |
1052
|
|
|
} |
1053
|
|
|
|
1054
|
|
|
/** |
1055
|
|
|
* Formats price to needed currency |
1056
|
|
|
* @param null|Currency $currency Currency to use in conversion, null for main shop currency |
1057
|
|
|
* @param boolean $oldPrice True if you want to return Old Price instead of price |
1058
|
|
|
* @param boolean $schemaOrg Return schema.org http://schema.org/Offer markup with span's |
1059
|
|
|
* @return string |
1060
|
|
|
*/ |
1061
|
|
|
public function formattedPrice($currency = null, $oldPrice = false, $schemaOrg = true) |
1062
|
|
|
{ |
1063
|
|
|
if ($currency === null) { |
1064
|
|
|
$currency = Currency::getMainCurrency(); |
1065
|
|
|
} |
1066
|
|
|
|
1067
|
|
|
$price = $this->convertedPrice($currency, $oldPrice); |
1068
|
|
|
|
1069
|
|
|
|
1070
|
|
|
$formatted_string = $currency->format($price); |
1071
|
|
|
if ($schemaOrg == true) { |
|
|
|
|
1072
|
|
|
return strtr( |
1073
|
|
|
' |
1074
|
|
|
<span itemtype="http://schema.org/Offer" itemprop="offers" itemscope> |
1075
|
|
|
<meta itemprop="priceCurrency" content="%iso_code%"> |
1076
|
|
|
<span itemprop="price" content="%price%"> |
1077
|
|
|
%formatted_string% |
1078
|
|
|
</span> |
1079
|
|
|
</span> |
1080
|
|
|
', |
1081
|
|
|
[ |
1082
|
|
|
'%iso_code%' => $currency->iso_code, |
1083
|
|
|
'%price%' => $price, |
1084
|
|
|
'%formatted_string%' => $formatted_string, |
1085
|
|
|
] |
1086
|
|
|
); |
1087
|
|
|
} else { |
1088
|
|
|
return $formatted_string; |
1089
|
|
|
} |
1090
|
|
|
|
1091
|
|
|
} |
1092
|
|
|
|
1093
|
|
|
/** |
1094
|
|
|
* Formats price in product's currency |
1095
|
|
|
* @param bool $oldPrice |
1096
|
|
|
* @param bool $schemaOrg |
1097
|
|
|
* @return string |
1098
|
|
|
*/ |
1099
|
|
|
public function nativeCurrencyPrice($oldPrice = false, $schemaOrg = true) |
1100
|
|
|
{ |
1101
|
|
|
$currency = Currency::findById($this->currency_id); |
1102
|
|
|
return $this->formattedPrice($currency, $oldPrice, $schemaOrg); |
1103
|
|
|
} |
1104
|
|
|
|
1105
|
|
|
public function getMeasure() |
1106
|
|
|
{ |
1107
|
|
|
$measure = Measure::findById($this->measure_id); |
1108
|
|
|
if (is_null($measure)) { |
1109
|
|
|
$measure = Measure::findById(Yii::$app->getModule('shop')->defaultMeasureId); |
1110
|
|
|
} |
1111
|
|
|
if (is_null($measure)) { |
1112
|
|
|
throw new Exception('Measure not found'); |
1113
|
|
|
} |
1114
|
|
|
return $measure; |
1115
|
|
|
} |
1116
|
|
|
|
1117
|
|
|
/** |
1118
|
|
|
* @param int|Category|null $category |
1119
|
|
|
* @param bool $asMainCategory |
1120
|
|
|
* @return bool |
1121
|
|
|
* @throws \yii\db\Exception |
1122
|
|
|
*/ |
1123
|
|
|
public function linkToCategory($category = null, $asMainCategory = false) |
1124
|
|
|
{ |
1125
|
|
|
if ($category instanceof Category) { |
1126
|
|
|
$category = $category->id; |
1127
|
|
|
} elseif (is_int($category) || is_string($category)) { |
1128
|
|
|
$category = intval($category); |
1129
|
|
|
} else { |
1130
|
|
|
return false; |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
|
|
if ($asMainCategory) { |
1134
|
|
|
$this->main_category_id = $category; |
1135
|
|
|
return $this->save(); |
1136
|
|
|
} else { |
1137
|
|
|
$tableName = $this->getObject()->categories_table_name; |
1138
|
|
|
$query = new Query(); |
1139
|
|
|
$query = $query->select(['id']) |
1140
|
|
|
->from($tableName) |
1141
|
|
|
->where(['category_id' => $category, 'object_model_id' => $this->id]) |
1142
|
|
|
->one(); |
1143
|
|
|
if (false === $query) { |
1144
|
|
|
try { |
1145
|
|
|
$result = Yii::$app->db->createCommand()->insert($tableName, [ |
1146
|
|
|
'category_id' => $category, |
1147
|
|
|
'object_model_id' => $this->id |
1148
|
|
|
])->execute(); |
1149
|
|
|
} catch (\yii\db\Exception $e) { |
1150
|
|
|
$result = false; |
1151
|
|
|
} |
1152
|
|
|
return boolval($result); |
1153
|
|
|
} |
1154
|
|
|
} |
1155
|
|
|
|
1156
|
|
|
return false; |
1157
|
|
|
} |
1158
|
|
|
|
1159
|
|
|
public function getCacheTags() |
1160
|
|
|
{ |
1161
|
|
|
$product = Yii::$container->get(Product::class); |
1162
|
|
|
$tags = [ |
1163
|
|
|
ActiveRecordHelper::getObjectTag(get_class($product), $this->id), |
1164
|
|
|
]; |
1165
|
|
|
$category = $this->getMainCategory(); |
1166
|
|
|
$tags [] = ActiveRecordHelper::getObjectTag(Category::className(), $category->id); |
|
|
|
|
1167
|
|
|
$categoryParentsIds = $category->getParentIds(); |
1168
|
|
|
foreach ($categoryParentsIds as $id) { |
1169
|
|
|
$tags [] = ActiveRecordHelper::getObjectTag(Category::className(), $id); |
|
|
|
|
1170
|
|
|
}; |
1171
|
|
|
|
1172
|
|
|
|
1173
|
|
|
return $tags; |
1174
|
|
|
} |
1175
|
|
|
|
1176
|
|
|
/** |
1177
|
|
|
* @return string |
1178
|
|
|
*/ |
1179
|
|
|
public function __toString() |
1180
|
|
|
{ |
1181
|
|
|
return ($this->className() . ':' . $this->id); |
|
|
|
|
1182
|
|
|
} |
1183
|
|
|
|
1184
|
|
|
/** |
1185
|
|
|
* @return string |
1186
|
|
|
*/ |
1187
|
|
|
public function jsonSerialize() |
1188
|
|
|
{ |
1189
|
|
|
return ($this->className() . ':' . $this->id); |
|
|
|
|
1190
|
|
|
} |
1191
|
|
|
} |
1192
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.