From 772a3ca4c30980bad4e17b998bf80f08a7cd39bf Mon Sep 17 00:00:00 2001 From: yarik Date: Sun, 6 Nov 2016 18:20:06 +0200 Subject: [PATCH] Big commit --- backend/controllers/SliderController.php | 6 ++---- common/modules/product/controllers/VariantController.php | 7 ++++++- common/modules/product/models/Import.php | 49 ++++++++++++++++++++++++++++++++++--------------- common/modules/product/models/Product.php | 446 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- common/modules/product/models/ProductCategory.php | 19 ++++++++++++------- common/modules/product/models/ProductImage.php | 9 +++------ common/modules/product/models/ProductSearch.php | 9 ++++++++- common/modules/product/models/ProductStock.php | 25 ++++++++++++++++++++----- common/modules/product/models/ProductVariant.php | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------- common/modules/product/models/ProductVariantSearch.php | 16 ---------------- common/modules/product/models/Stock.php | 36 +++++++++++++++++++++++------------- common/modules/product/models/StockLang.php | 2 +- common/modules/product/views/manage/_form.php | 7 ++++--- common/modules/product/views/variant/_form.php | 5 +---- common/modules/product/widgets/brandsCarouselWidget.php | 12 ++++++++---- common/modules/product/widgets/lastProducts.php | 16 ++++++++++------ common/modules/product/widgets/similarProducts.php | 18 +++++++++++------- common/modules/product/widgets/specialProducts.php | 24 +++++++++++++----------- common/modules/product/widgets/views/product_smart.php | 4 ++-- common/modules/rubrication/controllers/TaxGroupController.php | 11 ----------- common/modules/rubrication/controllers/TaxOptionController.php | 2 -- common/modules/rubrication/models/TaxGroup.php | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- common/modules/rubrication/models/TaxOption.php | 22 +++++++++++++++------- common/modules/rubrication/models/TaxOptionQuery.php | 34 ---------------------------------- 24 files changed, 606 insertions(+), 396 deletions(-) delete mode 100755 common/modules/rubrication/models/TaxOptionQuery.php diff --git a/backend/controllers/SliderController.php b/backend/controllers/SliderController.php index 97a71e8..5b955c8 100755 --- a/backend/controllers/SliderController.php +++ b/backend/controllers/SliderController.php @@ -82,8 +82,7 @@ if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect( [ - 'view', - 'id' => $model->id, + 'index', ] ); } else { @@ -112,8 +111,7 @@ if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect( [ - 'view', - 'id' => $model->id, + 'index', ] ); } else { diff --git a/common/modules/product/controllers/VariantController.php b/common/modules/product/controllers/VariantController.php index bd13fa0..841091d 100755 --- a/common/modules/product/controllers/VariantController.php +++ b/common/modules/product/controllers/VariantController.php @@ -234,7 +234,12 @@ $stocks = Stock::find() ->joinWith('lang') ->where([ 'stock_lang.title' => $stock_names ]) - ->indexBy('title') + ->indexBy(function($row) { + /** + * @var Stock $row + */ + return $row->lang->title; + }) ->all(); foreach ($productStocks as $stockName => $quantity) { $quantity = (int) $quantity; diff --git a/common/modules/product/models/Import.php b/common/modules/product/models/Import.php index a097bc7..3fc6a61 100755 --- a/common/modules/product/models/Import.php +++ b/common/modules/product/models/Import.php @@ -8,7 +8,12 @@ use Yii; use yii\base\Model; use yii\helpers\ArrayHelper; - + + /** + * Class Import + * + * @package common\modules\product\models + */ class Import extends Model { /** @@ -410,13 +415,13 @@ /** * Save ProductVariants * - * @param array $data ProductVariats data + * @param array $data ProductVariats data * @param float $product_cost_old Old price - * @param int $product_id Product ID - * @param array $category_id Ca + * @param int $product_id Product ID + * @param array $category_id Ca * @param float|null $product_cost * - * @return array + * @return int[] Array of ProductVariants IDs * @throws \Exception */ private function saveVariants( @@ -503,10 +508,14 @@ return $MOD_ARRAY; } - // private function debug($start_time, $message) { - // echo $message.': '.(time()-$start_time).'s passed'; - // } - + /** + * Perform product import + * + * @param int $from Begin row + * @param null $limit Row limit + * + * @return array|bool Array if OK, false if error + */ public function goProducts($from = 0, $limit = null) { set_time_limit(0); @@ -713,6 +722,13 @@ return $result; } + /** + * Get import file + * + * @param string $file_type + * + * @return bool|resource false if File not found and file resource if OK + */ private function getProductsFile($file_type) { $filename = Yii::getAlias('@uploadDir') . '/' . Yii::getAlias('@' . $file_type); @@ -724,11 +740,13 @@ } /** - * @param $filters array of filters like [['pol'='мужской'],['god' = - * '2013'],['volume'='25 л']*['size'='49 x 30 x - * 20см'],['composition'='600D полиэстер']] - * @param int $level 0 for products and 1 for product variant - * @param $catalog_names array catalogs id + * Save filters + * + * @param array $filters array of filters like [['pol'='мужской'],['god' = + * '2013'],['volume'='25 л']*['size'='49 x 30 x + * 20см'],['composition'='600D полиэстер']] + * @param int $level 0 for products and 1 for product variant + * @param int[] $catalog_names array catalogs id * * @return array * @throws \Exception @@ -819,4 +837,5 @@ } return $options; } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/common/modules/product/models/Product.php b/common/modules/product/models/Product.php index 6399bad..1e58282 100755 --- a/common/modules/product/models/Product.php +++ b/common/modules/product/models/Product.php @@ -7,46 +7,58 @@ use common\models\ProductToRating; use common\modules\comment\models\CommentModel; use common\modules\language\behaviors\LanguageBehavior; - use common\modules\language\models\Language; use common\modules\rubrication\models\TaxGroup; + use common\modules\rubrication\models\TaxGroupToCategory; use common\modules\rubrication\models\TaxOption; use Yii; + use yii\base\InvalidParamException; use yii\db\ActiveQuery; use yii\db\ActiveRecord; use yii\helpers\ArrayHelper; + use yii\web\NotFoundHttpException; use yii\web\Request; /** * This is the model class for table "{{%product}}". * - * @property integer $brand_id - * @property integer $id - * @property Category $category - * @property Category[] $categories - * @property ProductVariant[] $variants - * @property ProductVariant $variant - * @property boolean $is_top - * @property boolean $is_new - * @property boolean $is_discount - * @property ProductToRating $averageRating - * @property TaxGroup[] $properties - * @property ProductVariant $enabledVariant - * @property ProductVariant[] $enabledVariants - * @property string $video - * @property TaxOption[] $options - * @property Brand $brand - * @property TaxOption[] $filters - * @property ProductVariant[] $variantsWithFilters - * @property string $remote_id - * @property string $fullname + * @property integer $brand_id + * @property integer $id + * @property Category $category + * @property Category[] $categories + * @property ProductVariant $variant + * @property ProductVariant[] $variants + * @property ProductVariant $productVariant + * @property ProductVariant[] $productVariants + * @property boolean $is_top + * @property boolean $is_new + * @property boolean $is_discount + * @property ProductToRating $averageRating + * @property TaxGroup[] $properties + * @property ProductVariant $enabledVariant + * @property ProductVariant[] $enabledVariants + * @property string $video + * @property TaxOption[] $options + * @property Brand $brand + * @property TaxOption[] $filters + * @property ProductVariant[] $variantsWithFilters + * @property string $remote_id + * @property string $fullname + * @property float $variantPrice + * @property float $enabledVariantPrice + * @property array $categoryNames + * @property Stock[] $stocks + * @property ProductStock[] $productStocks + * @property int $quantity + * @property TaxGroupToCategory[] $categoriesToGroups + * @property TaxGroup[] $taxGroupsByLevel * * From language behavior * - * @property ProductLang $lang - * @property ProductLang[] $langs - * @property ProductLang $objectLang - * @property string $ownerKey - * @property string $langKey - * @property ProductLang[] $modelLangs - * @property bool $transactionStatus + * @property ProductLang $lang + * @property ProductLang[] $langs + * @property ProductLang $objectLang + * @property string $ownerKey + * @property string $langKey + * @property ProductLang[] $modelLangs + * @property bool $transactionStatus * @method string getOwnerKey() * @method void setOwnerKey( string $value ) * @method string getLangKey() @@ -60,9 +72,9 @@ * @method bool getTransactionStatus() * * End language behavior * * * From multipleImage behavior - * @property ProductImage $image - * @property ProductImage[] $images - * @property array imagesConfig + * @property ProductImage $image + * @property ProductImage[] $images + * @property array imagesConfig * @method ActiveQuery getImage() * @method ActiveQuery getImages() * @method array getImagesConfig() @@ -86,7 +98,7 @@ 'directory' => 'products', 'column' => 'image', 'links' => [ - 'product_id' => 'id', + 'id' => 'product_id', ], 'model' => ProductImage::className(), ], @@ -102,7 +114,7 @@ 'config' => [ 'caption' => 'image', 'delete_action' => '/product/manage/delete-image', - 'id' => 'product_image_id', + 'id' => 'id', ], ], 'language' => [ @@ -164,9 +176,7 @@ 'id' => Yii::t('product', 'ID'), 'brand_id' => Yii::t('product', 'Brand'), 'categories' => Yii::t('product', 'Categories'), - // relation behavior field 'category' => Yii::t('product', 'Category'), - // relation behavior field 'image' => Yii::t('product', 'Image'), 'images' => Yii::t('product', 'Images'), 'video' => Yii::t('product', 'Video embeded'), @@ -178,6 +188,8 @@ } /** + * Get Brand query to current Product + * * @return \yii\db\ActiveQuery */ public function getBrand() @@ -186,6 +198,8 @@ } /** + * Get ProductVariant query to current Product + * * @return \yii\db\ActiveQuery */ public function getVariant() @@ -194,62 +208,135 @@ } /** + * Synonim of getVariant() + * + * @see Product::getVariant() * @return \yii\db\ActiveQuery */ - public function getEnabledVariant() + public function getProductVariant() { - return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ]) - ->andOnCondition( - [ - '!=', - ProductVariant::tableName() . '.stock', - 0, - ] - ); + return $this->getVariant(); } - public function getVariantPrice() + /** + * Get ProductVariants query to current Product + * + * @return \yii\db\ActiveQuery + */ + public function getVariants() { - return $this->variant->price; + return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]); } - public function getEnabledVariantPrice() + /** + * Synonim of getVariants() + * + * @see Product::getVariants() + * @return \yii\db\ActiveQuery + */ + public function getProductVariants() { - return $this->enabledVariants[ 0 ]->price; + return $this->getVariant(); } /** + * Get ProductVariant query fetching only available in stock to current Product + * + * @see Product::getVariant() * @return \yii\db\ActiveQuery */ - public function getVariants() + public function getEnabledVariant() { - return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]); + return $this->hasOne(ProductVariant::className(), [ 'product_id' => 'id' ]) + ->andWhere( + [ + '!=', + ProductVariant::tableName() . '.stock', + 0, + ] + ); } + /** + * Get ProductVariants query fetching only available in stock to current Product + * + * @see Product::getVariants() + * @return \yii\db\ActiveQuery + */ public function getEnabledVariants() { return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]) - ->andOnCondition( + ->andWhere( [ '!=', ProductVariant::tableName() . '.stock', 0, ] - ) - ->joinWith('image'); + ); + } + + /** + * Get random ProductVariant price or 0 if not exist + * + * @param bool $exception Whether to throw exception if variant not exist + * + * @return float + * @throws \yii\web\NotFoundHttpException + */ + public function getVariantPrice(bool $exception = false): float + { + if (!empty( $this->variant )) { + return $this->variant->price; + } elseif ($exception) { + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got variants'); + } else { + return 0; + } } - public function setVariants($variants) + /** + * Get random ProductVariant that in stock price or 0 or exception if not exist + * + * @param bool $exception Whether to throw exception if variant not exist + * + * @return float + * @throws \yii\web\NotFoundHttpException + */ + public function getEnabledVariantPrice(bool $exception = false): float { - $this->variants = $variants; + if (!empty( $this->enabledVariant )) { + return $this->enabledVariant->price; + } elseif ($exception) { + throw new NotFoundHttpException('Product with ID ' . $this->id . ' hasn\'t got enabled variants'); + } else { + return 0; + } } - public function getFullname() + /** + * Get Product name concatenated with Brand name + * + * @return string + */ + public function getFullname():string { return empty( $this->brand ) ? $this->lang->title : $this->brand->lang->title . ' ' . $this->lang->title; } /** + * Get Category query for current Product + * + * @return ActiveQuery + */ + public function getCategory() + { + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]) + ->viaTable('product_category', [ 'product_id' => 'id' ]); + } + + /** + * Get Categories query for current Product + * * @return ActiveQuery */ public function getCategories() @@ -258,19 +345,30 @@ ->viaTable('product_category', [ 'product_id' => 'id' ]); } - public function getCategoriesNames() + /** + * @param bool $index + * + * @return array + */ + public function getCategoryNames(bool $index = false): array { - $result = []; - foreach ($this->categories as $category) { - $result[] = $category->lang->title; + if ($index) { + $result = ArrayHelper::map($this->categories, 'id', 'lang.title'); + } else { + $result = ArrayHelper::getColumn($this->categories, 'lang.title'); } return $result; } + /** + * Get ProductVariants query with lang, filters and image for current Product + * + * @return ActiveQuery + */ public function getVariantsWithFilters() { return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]) - ->joinWith('lang', true, 'INNER JOIN') + ->joinWith('lang') ->with( [ 'filters', @@ -279,50 +377,11 @@ ); } - public function getVariantsFilter() - { - return $this->hasMany(ProductVariant::className(), [ 'product_id' => 'id' ]) - ->joinWith('lang') - ->joinWith( - [ - 'options variant_options' => function ($query) { - /** - * @var ActiveQuery $query - */ - $query->joinWith([ 'langs variant_options_lang' ]) - ->andWhere( - [ 'variant_options_lang.language_id' => Language::getCurrent()->id ] - ) - ->joinWith( - [ - 'taxGroup variant_options_group' => function ($subquery) { - /** - * @var ActiveQuery $subquery - */ - $subquery->joinWith([ 'langs variant_options_group_lang' ]) - ->andWhere( - [ - 'variant_options_group_lang.language_id' => Language::getCurrent( - )->id, - ] - ); - }, - ] - ); - }, - ] - ); - } - /** + * Get TaxOptions query for current Product + * * @return ActiveQuery */ - public function getCategory() - { - return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]) - ->viaTable('product_category', [ 'product_id' => 'id' ]); - } - public function getOptions() { return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) @@ -330,9 +389,24 @@ } /** + * Get TaxOptions query for current Product joined with TaxGroups + * + * @see Product::getOptions() + * @return ActiveQuery + */ + public function getFilters() + { + return $this->getOptions() + ->joinWith('taxGroup.lang') + ->joinWith('lang'); + } + + /** + * Get all TaxGroups for current Product filled with $customOptions that satisfy current Product + * * @return TaxGroup[] */ - public function getProperties() + public function getProperties(): array { $groups = $options = []; foreach ($this->getOptions() @@ -341,7 +415,7 @@ /** * @var TaxOption $option */ - $options[ $option->tax_group_id ][] = $option; + $options[ $option[ 'tax_group_id' ] ][] = $option; } foreach (TaxGroup::find() ->where([ 'id' => array_keys($options) ]) @@ -351,60 +425,52 @@ * @var TaxGroup $group */ if (!empty( $options[ $group->id ] )) { - $group->options = $options[ $group->id ]; - $groups[] = $group; - } - } - return $groups; - } - - public function getActiveProperties($category_id) - { - $groups = $options = []; - foreach ($this->options as $option) { - $options[ $option->tax_group_id ][] = $option; - } - /** - * @var TaxGroup[] $taxGroups - */ - $taxGroups = TaxGroup::find() - ->joinWith('categories') - ->where( - [ - 'tax_group.id' => array_keys($options), - 'tax_group.display' => true, - 'category.id' => $category_id, - ] - ) - ->all(); - - foreach ($taxGroups as $group) { - if (!empty( $options[ $group->id ] )) { - $group->options = $options[ $group->id ]; + $group->customOptions = $options[ $group->id ]; $groups[] = $group; } } return $groups; } + /** + * Get Stock query where current Product is in stock + * + * @return ActiveQuery + */ public function getStocks() { - return $this->hasMany(Stock::className(), [ 'id' => 'product_id' ]) - ->via('variants'); + return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ]) + ->via('productStocks'); } + /** + * Get ProductStocks query for current Product + * + * @return ActiveQuery + */ public function getProductStocks() { return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]) ->via('variants'); } - public function getQuantity() + /** + * Get quantity of all ProductVariants for current Product + * + * @see Product::getProductStocks() + * @return int + */ + public function getQuantity():int { return $this->getProductStocks() ->sum('quantity'); } + /** + * Override Categories and TaxOptions + * + * @inheritdoc + */ public function afterSave($insert, $changedAttributes) { parent::afterSave($insert, $changedAttributes); @@ -424,37 +490,15 @@ $this->link('options', $option); } } - - if (!empty( $this->variants )) { - $todel = []; - foreach ($this->variants ? : [] as $_variant) { - /** - * @var ProductVariant $_variant - */ - $todel[ $_variant->id ] = $_variant->id; - } - foreach ($this->variants as $_variant) { - if (!is_array($_variant)) { - return; - } - if (!empty( $_variant[ 'id' ] )) { - unset( $todel[ $_variant[ 'id' ] ] ); - $model = ProductVariant::findOne($_variant[ 'id' ]); - } else { - $model = new ProductVariant(); - } - $_variant[ 'product_id' ] = $this->id; - $model->load([ 'ProductVariant' => $_variant ]); - $model->product_id = $this->id; - $model->save(); - } - if (!empty( $todel )) { - ProductVariant::deleteAll([ 'id' => $todel ]); - } - } } - public function recalculateRating() + /** + * Recalculate rating for artboxcomment module + * + * @todo Rewrite with behavior + * @return bool + */ + public function recalculateRating():bool { /** * @var ProductToRating $averageRating @@ -484,6 +528,12 @@ } } + /** + * Get CommmentModel query for artboxcomment module + * + * @todo Rewrite with behavior + * @return ActiveQuery + */ public function getComments() { return $this->hasMany(CommentModel::className(), [ 'entity_id' => 'id' ]) @@ -496,39 +546,67 @@ ); } + /** + * Get ProductToRating query in order to get average rating for current Product + * + * @return \yii\db\ActiveQuery + */ public function getAverageRating() { return $this->hasOne(ProductToRating::className(), [ 'product_id' => 'id' ]); } - public function getTaxGroupsByLevel($level) + /** + * Get TaxGroupToCategories query via product_category table + * + * @return ActiveQuery + */ + public function getCategoriesToGroups() { - $categories = ArrayHelper::getColumn($this->categories, 'id'); - return TaxGroup::find() - ->distinct() - ->innerJoin( - 'tax_group_to_category', - 'tax_group_to_category.tax_group_id = tax_group.id' - ) - ->andWhere([ 'tax_group_to_category.category_id' => $categories ]) - ->andWhere([ 'level' => $level ]); + return $this->hasMany(TaxGroupToCategory::className(), [ 'category_id' => 'category_id' ]) + ->viaTable('product_category', [ 'product_id' => 'id' ]); } + /** + * Get TaxGroups query for current Product according to level + * * 0 - Product Tax Groups + * * 1 - ProductVariant Tax Groups + * + * @param int $level + * + * @return ActiveQuery + * @throws InvalidParamException + */ + public function getTaxGroupsByLevel(int $level = 0) + { + if ($level !== 0 && $level !== 1) { + throw new InvalidParamException( + 'Level must be 0 for Product Tax Groups or 1 for Product Variant Tax Groups' + ); + } + return $this->hasMany(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) + ->via('categoriesToGroups') + ->where([ 'level' => $level ]) + ->distinct(); + } + + /** + * Setter for Categories + * + * @param array $values + */ public function setCategories($values) { $this->categories = $values; } + /** + * Setter for Options + * + * @param array $values + */ public function setOptions($values) { $this->options = $values; } - - public function getFilters() - { - return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) - ->viaTable('product_option', [ 'product_id' => 'id' ]) - ->joinWith('taxGroup.lang', true, 'INNER JOIN') - ->joinWith('lang', true, 'INNER JOIN'); - } } diff --git a/common/modules/product/models/ProductCategory.php b/common/modules/product/models/ProductCategory.php index 0c7aee9..d351b69 100755 --- a/common/modules/product/models/ProductCategory.php +++ b/common/modules/product/models/ProductCategory.php @@ -2,21 +2,17 @@ namespace common\modules\product\models; - use common\modules\rubrication\models\TaxOption; use Yii; use yii\db\ActiveRecord; /** * This is the model class for table "{{%product_category}}". - * @property integer $product_id - * @property integer $category_id - * @property TaxOption $devCategory + * + * @property integer $product_id + * @property integer $category_id */ class ProductCategory extends ActiveRecord { - - public $alias = 'product_categories'; - /** * @inheritdoc */ @@ -66,4 +62,13 @@ ]; } + public function getCategory() + { + return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]); + } + + public function getProduct() + { + return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); + } } diff --git a/common/modules/product/models/ProductImage.php b/common/modules/product/models/ProductImage.php index b0c66b3..f5139de 100755 --- a/common/modules/product/models/ProductImage.php +++ b/common/modules/product/models/ProductImage.php @@ -9,7 +9,7 @@ /** * This is the model class for table "product_image". * - * @property integer $product_image_id + * @property integer $id * @property integer $product_id * @property integer $product_variant_id * @property string $image @@ -52,7 +52,7 @@ ], [ [ - 'product_image_id', + 'id', 'product_id', 'product_variant_id', ], @@ -90,7 +90,7 @@ public function attributeLabels() { return [ - 'product_image_id' => Yii::t('product', 'Product Image ID'), + 'id' => Yii::t('product', 'Product Image ID'), 'product_id' => Yii::t('product', 'Product ID'), 'product_variant_id' => Yii::t('product', 'Product Variant ID'), 'product' => Yii::t('product', 'Product'), @@ -107,9 +107,6 @@ public function getProduct() { $return = $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); - if (empty( $return )) { - $return = $this->productVariant->product_id; - } return $return; } diff --git a/common/modules/product/models/ProductSearch.php b/common/modules/product/models/ProductSearch.php index db5353b..5ed506d 100755 --- a/common/modules/product/models/ProductSearch.php +++ b/common/modules/product/models/ProductSearch.php @@ -89,7 +89,6 @@ */ public function search($params) { - $query = Product::find(); $query->select( [ @@ -150,6 +149,14 @@ ], ] ); + + $this->load($params); + + if(!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } if (isset( $this->is_top )) { $query->andWhere( diff --git a/common/modules/product/models/ProductStock.php b/common/modules/product/models/ProductStock.php index 50f8a45..b8a3f1b 100755 --- a/common/modules/product/models/ProductStock.php +++ b/common/modules/product/models/ProductStock.php @@ -13,10 +13,11 @@ * @property Product $product * @property ProductVariant $productVariant * @property Stock $stock + * @property string $title */ class ProductStock extends ActiveRecord { - + protected $title; /** * @inheritdoc */ @@ -90,17 +91,28 @@ return $this->hasOne(ProductVariant::className(), [ 'id' => 'product_variant_id' ]); } - public function getName() + /** + * Get Stock title, tries to get from Stock lang + * + * @return string + */ + public function getTitle(): string { - return ( !empty( $this->stock ) ) ? $this->stock->title : ''; + if (!empty( $this->title )) { + return $this->title; + } elseif (!empty( $this->stock )) { + return $this->stock->lang->title; + } else { + return ''; + } } /** - * @todo Check if needed + * Set Stock title, will be saved to Stock table * * @param mixed $value */ - public function setName($value) + public function setTitle(string $value) { $this->title = $value; } @@ -113,6 +125,9 @@ return $this->hasOne(Stock::className(), [ 'id' => 'stock_id' ]); } + /** + * @inheritdoc + */ public static function primaryKey() { return [ diff --git a/common/modules/product/models/ProductVariant.php b/common/modules/product/models/ProductVariant.php index 3006d36..a8ee140 100755 --- a/common/modules/product/models/ProductVariant.php +++ b/common/modules/product/models/ProductVariant.php @@ -8,15 +8,14 @@ use common\modules\rubrication\models\TaxGroup; use common\modules\rubrication\models\TaxOption; use Yii; + use yii\base\InvalidParamException; use yii\db\ActiveQuery; use yii\db\ActiveRecord; - use yii\helpers\ArrayHelper; use yii\web\Request; /** * This is the model class for table "product_variant". * - * @todo Refactor * @property integer $id * @property integer $product_id * @property integer $remote_id @@ -25,12 +24,19 @@ * @property double $price_old * @property double $stock * @property integer $product_unit_id - * @property string|null $fullname + * @property string $fullname * @property TaxOption[] $options * @property ProductUnit $productUnit * @property Product $product * @property Category[] $categories + * @property Category $category * @property TaxOption[] $filters + * @property ProductStock[] $productStocks + * @property int $quantity + * @property ProductStock[] $variantStocks + * @property Stock[] $stocks + * @property TaxGroup[] $properties + * @property TaxGroup[] $taxGroupsByLevel * * From language behavior * * @property ProductVariantLang $lang * @property ProductVariantLang[] $langs @@ -63,10 +69,9 @@ */ class ProductVariant extends ActiveRecord { - public $sumCost; - - public $productName; - + /** + * @var int[] $options + */ private $options; /** @var array $_images */ @@ -98,7 +103,7 @@ 'column' => 'image', 'links' => [ 'product_id' => 'product_id', - 'product_variant_id' => 'id', + 'id' => 'product_variant_id', ], 'model' => ProductImage::className(), ], @@ -111,7 +116,7 @@ 'config' => [ 'caption' => 'image', 'delete_action' => '/product/variant/delete-image', - 'id' => 'product_image_id', + 'id' => 'id', ], ], ]; @@ -165,6 +170,13 @@ 'targetClass' => ProductUnit::className(), 'targetAttribute' => [ 'product_unit_id' => 'id' ], ], + [ + [ 'product_id' ], + 'exist', + 'skipOnError' => true, + 'targetClass' => Product::className(), + 'targetAttribute' => [ 'product_id' => 'id' ], + ], ]; } @@ -203,63 +215,104 @@ return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]); } - public function getProductStock() + /** + * @return \yii\db\ActiveQuery + */ + public function getProductStocks() { return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]); } - public function getQuantity() - { - return ProductStock::find() - ->where([ 'product_variant_id' => $this->id ]) - ->sum('quantity'); - } - - public function getStockCaption() + /** + * Get qunatity for current ProductVariant + * If $recalculate set to true will recalculate stock via product_stock table + * + * @param bool $recalculate + * + * @return int + */ + public function getQuantity(bool $recalculate = false): int { - return is_null($this->stock) ? '∞' : ( $this->stock > 0 ? Yii::t('product', 'Enable') : Yii::t( - 'product', - 'Disable' - ) ); + if (!$recalculate) { + return $this->stock; + } else { + $quantity = $this->getProductStocks() + ->sum('quantity'); + if (empty( $quantity )) { + $this->stock = 0; + } else { + $this->stock = (int) $quantity; + } + $this->save(false, [ 'stock' ]); + return $this->stock; + } } + /** + * Get ProductStocks query woth preloaded Stocks for current ProductVariant + * **Used in dynamic fields in product variant form** + * + * @return ActiveQuery + */ public function getVariantStocks() { - return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'id' ]) + return $this->getProductStocks() ->joinWith('stock'); } + /** + * @return ActiveQuery + */ public function getStocks() { return $this->hasMany(Stock::className(), [ 'id' => 'stock_id' ]) - ->viaTable(ProductStock::tableName(), [ 'product_variant_id' => 'id' ]); + ->via('productStocks'); } - public function getFilters() + /** + * @return ActiveQuery + */ + public function getOptions() { return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) - ->viaTable('product_variant_option', [ 'product_variant_id' => 'id' ]) - ->joinWith('taxGroup.lang', true, 'INNER JOIN') - ->joinWith('lang', true, 'INNER JOIN'); + ->viaTable('product_variant_option', [ 'product_variant_id' => 'id' ]); } - public function getFullname() + /** + * Get TaxOptions with preloaded TaxGroups for current ProductVariant + * + * @return ActiveQuery + */ + public function getFilters() { - return empty( $this->product ) ? null : ( $this->product->lang->title . ( empty( $this->lang->title ) ? '' : ' ' . $this->lang->title ) ); + return $this->getOptions() + ->joinWith('taxGroup.lang') + ->joinWith('lang'); } - public function setOptions($values) + /** + * Get Product title concanated with current ProductVariant title + * + * @return string + */ + public function getFullname(): string { - $this->options = $values; + return $this->product->lang->title . ' ' . $this->lang->title; } - public function getOptions() + /** + * Set Options to override previous + * + * @param int[] $values + */ + public function setOptions($values) { - return $this->hasMany(TaxOption::className(), [ 'id' => 'option_id' ]) - ->viaTable('product_variant_option', [ 'product_variant_id' => 'id' ]); + $this->options = $values; } /** + * Get all TaxGroups for current ProductVariant filled with $customOptions that satisfy current ProductVariant + * * @return TaxGroup[] */ public function getProperties() @@ -282,7 +335,7 @@ * @var TaxGroup $group */ if (!empty( $options[ $group->id ] )) { - $group->options = $options[ $group->id ]; + $group->customOptions = $options[ $group->id ]; $groups[] = $group; } } @@ -290,7 +343,7 @@ } /** - * @todo Check if needed + * Set stocks to override existing in product_stock table * * @param mixed $stocks */ @@ -299,29 +352,37 @@ $this->stocks = (array) $stocks; } + /** + * @return ActiveQuery + */ public function getCategory() { return $this->hasOne(Category::className(), [ 'id' => 'category_id' ]) ->viaTable('product_category', [ 'product_id' => 'product_id' ]); } + /** + * @return ActiveQuery + */ public function getCategories() { return $this->hasMany(Category::className(), [ 'id' => 'category_id' ]) ->viaTable('product_category', [ 'product_id' => 'product_id' ]); } - public function getTaxGroupsByLevel($level) + /** + * Get TaxGroups query for current ProductVariant according to level + * * 0 - Product Tax Groups + * * 1 - ProductVariant Tax Groups + * + * @param int $level + * + * @return ActiveQuery + * @throws InvalidParamException + */ + public function getTaxGroupsByLevel(int $level = 0) { - $categories = ArrayHelper::getColumn($this->categories, 'id'); - return TaxGroup::find() - ->distinct() - ->innerJoin( - 'tax_group_to_category', - 'tax_group_to_category.tax_group_id = tax_group.id' - ) - ->where([ 'tax_group_to_category.category_id' => $categories ]) - ->where([ 'level' => $level ]); + return $this->product->getTaxGroupsByLevel($level); } public function afterSave($insert, $changedAttributes) diff --git a/common/modules/product/models/ProductVariantSearch.php b/common/modules/product/models/ProductVariantSearch.php index 6522ddf..e05a45f 100755 --- a/common/modules/product/models/ProductVariantSearch.php +++ b/common/modules/product/models/ProductVariantSearch.php @@ -134,20 +134,4 @@ return $dataProvider; } - - /** - * @param string $sku - * - * @return ProductVariant|null - */ - public static function findBySku($sku) - { - /** - * @var ProductVariant|null $result - */ - $result = ProductVariant::find() - ->andWhere([ 'sku' => $sku ]) - ->one(); - return $result; - } } diff --git a/common/modules/product/models/Stock.php b/common/modules/product/models/Stock.php index f2e2443..9a4603f 100755 --- a/common/modules/product/models/Stock.php +++ b/common/modules/product/models/Stock.php @@ -7,20 +7,22 @@ use yii\db\ActiveQuery; use yii\db\ActiveRecord; use yii\web\Request; - + /** * This is the model class for table "stock". * - * @property integer $id - * @property ProductStock[] $productStocks + * @property integer $id + * @property ProductStock[] $productStocks + * @property ProductVariant[] $productVariants + * @property Product[] $products * * From language behavior * - * @property StockLang $lang - * @property StockLang[] $langs - * @property StockLang $objectLang - * @property string $ownerKey - * @property string $langKey - * @property StockLang[] $modelLangs - * @property bool $transactionStatus + * @property StockLang $lang + * @property StockLang[] $langs + * @property StockLang $objectLang + * @property string $ownerKey + * @property string $langKey + * @property StockLang[] $modelLangs + * @property bool $transactionStatus * @method string getOwnerKey() * @method void setOwnerKey( string $value ) * @method string getLangKey() @@ -36,7 +38,6 @@ */ class Stock extends ActiveRecord { - /** * @inheritdoc */ @@ -44,7 +45,7 @@ { return 'stock'; } - + public function behaviors() { return [ @@ -60,21 +61,30 @@ public function attributeLabels() { return [ - 'id' => Yii::t('product', 'Stock ID'), + 'id' => Yii::t('product', 'Stock ID'), ]; } + /** + * @return \yii\db\ActiveQuery + */ public function getProductStocks() { return $this->hasMany(ProductStock::className(), [ 'stock_id' => 'id' ]); } + /** + * @return ActiveQuery + */ public function getProductVariants() { return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ]) ->via('productStocks'); } + /** + * @return ActiveQuery + */ public function getProducts() { return $this->hasMany(Product::className(), [ 'id' => 'product_id' ]) diff --git a/common/modules/product/models/StockLang.php b/common/modules/product/models/StockLang.php index 0cc04c9..7088596 100644 --- a/common/modules/product/models/StockLang.php +++ b/common/modules/product/models/StockLang.php @@ -68,7 +68,7 @@ 'exist', 'skipOnError' => true, 'targetClass' => Stock::className(), - 'targetAttribute' => [ 'id' => 'stock_id' ], + 'targetAttribute' => [ 'stock_id' => 'id' ], ], [ [ 'language_id' ], diff --git a/common/modules/product/views/manage/_form.php b/common/modules/product/views/manage/_form.php index 193092a..efbab32 100755 --- a/common/modules/product/views/manage/_form.php +++ b/common/modules/product/views/manage/_form.php @@ -1,6 +1,7 @@ field($model, 'brand_id') ->dropDownList( ArrayHelper::map( - ProductHelper::getBrands() - ->with('lang') - ->all(), + Brand::find() + ->with('lang') + ->all(), 'id', 'lang.title' ), diff --git a/common/modules/product/views/variant/_form.php b/common/modules/product/views/variant/_form.php index c37da15..1755405 100755 --- a/common/modules/product/views/variant/_form.php +++ b/common/modules/product/views/variant/_form.php @@ -167,10 +167,7 @@ $(".dynamicform_wrapper").on("limitReached", function(e, item) { ->all(), 'id', 'lang.title' - ), - [ - 'prompt' => Yii::t('product', 'Unit'), - ] + ) ) ->label(Yii::t('product', 'Unit')) ?> diff --git a/common/modules/product/widgets/brandsCarouselWidget.php b/common/modules/product/widgets/brandsCarouselWidget.php index 745972e..ae828e0 100755 --- a/common/modules/product/widgets/brandsCarouselWidget.php +++ b/common/modules/product/widgets/brandsCarouselWidget.php @@ -18,8 +18,12 @@ $brands = Brand::find() ->with('lang') ->all(); - return $this->render('brandsCarousel', [ - 'brands' => $brands, - ]); + return $this->render( + 'brandsCarousel', + [ + 'brands' => $brands, + ] + ); } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/common/modules/product/widgets/lastProducts.php b/common/modules/product/widgets/lastProducts.php index 7be2e70..acec3bc 100755 --- a/common/modules/product/widgets/lastProducts.php +++ b/common/modules/product/widgets/lastProducts.php @@ -15,10 +15,14 @@ public function run() { - return $this->render('products_block', [ - 'title' => \Yii::t('product', 'Вы недавно просматривали'), - 'class' => 'last-products', - 'products' => ProductHelper::getLastProducts(true), - ]); + return $this->render( + 'products_block', + [ + 'title' => \Yii::t('product', 'Вы недавно просматривали'), + 'class' => 'last-products', + 'products' => ProductHelper::getLastProducts(true), + ] + ); } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/common/modules/product/widgets/similarProducts.php b/common/modules/product/widgets/similarProducts.php index a5fa359..2376e3f 100755 --- a/common/modules/product/widgets/similarProducts.php +++ b/common/modules/product/widgets/similarProducts.php @@ -24,14 +24,18 @@ { $products = ProductHelper::getSimilarProducts($this->product, $this->count); - if(!$this->title) { + if (!$this->title) { $this->title = Yii::t('product', 'Similar products'); } - return $this->render('products_block', [ - 'title' => $this->title, - 'class' => 'similar-products', - 'products' => $products, - ]); + return $this->render( + 'products_block', + [ + 'title' => $this->title, + 'class' => 'similar-products', + 'products' => $products, + ] + ); } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/common/modules/product/widgets/specialProducts.php b/common/modules/product/widgets/specialProducts.php index 880ba51..219bdca 100755 --- a/common/modules/product/widgets/specialProducts.php +++ b/common/modules/product/widgets/specialProducts.php @@ -13,8 +13,6 @@ public $count = 8; - public $sort = 'default'; - public $title; public function init() @@ -24,10 +22,10 @@ public function run() { - $products = ProductHelper::getSpecialProducts($this->type, $this->count, $this->sort); + $products = ProductHelper::getSpecialProducts($this->type, $this->count); - if(!$this->title) { - switch($this->type) { + if (!$this->title) { + switch ($this->type) { case 'top': $this->title = Yii::t('product', 'Top products'); break; @@ -40,10 +38,14 @@ } } - return $this->render('products_block', [ - 'title' => $this->title, - 'class' => $this->type, - 'products' => $products, - ]); + return $this->render( + 'products_block', + [ + 'title' => $this->title, + 'class' => $this->type, + 'products' => $products, + ] + ); } - } \ No newline at end of file + } + \ No newline at end of file diff --git a/common/modules/product/widgets/views/product_smart.php b/common/modules/product/widgets/views/product_smart.php index 81ff5e9..187dd85 100755 --- a/common/modules/product/widgets/views/product_smart.php +++ b/common/modules/product/widgets/views/product_smart.php @@ -69,9 +69,9 @@
  • Бренд: brand->lang->title ?>
  • - getActiveProperties($product->category->id) as $group): ?> + getProperties() as $group): ?>
  • - title ?> options as $option ) : ?> value ?> + lang->title ?> customOptions as $option ) : ?> lang->value ?>
  • diff --git a/common/modules/rubrication/controllers/TaxGroupController.php b/common/modules/rubrication/controllers/TaxGroupController.php index 4d4ec63..0738835 100755 --- a/common/modules/rubrication/controllers/TaxGroupController.php +++ b/common/modules/rubrication/controllers/TaxGroupController.php @@ -2,7 +2,6 @@ namespace common\modules\rubrication\controllers; - use common\modules\rubrication\models\TaxOption; use Yii; use common\modules\rubrication\models\TaxGroup; use yii\data\ActiveDataProvider; @@ -130,16 +129,6 @@ ]); } - /* - * Rebuilp MP-params for group options - */ - public function actionRebuild($id) - { - TaxOption::find() - ->rebuildMP($id); - return $this->redirect([ 'index' ]); - } - /** * Finds the TaxGroup model based on its primary key value. * If the model is not found, a 404 HTTP exception will be thrown. diff --git a/common/modules/rubrication/controllers/TaxOptionController.php b/common/modules/rubrication/controllers/TaxOptionController.php index 20bcba4..cfbfc1d 100755 --- a/common/modules/rubrication/controllers/TaxOptionController.php +++ b/common/modules/rubrication/controllers/TaxOptionController.php @@ -113,8 +113,6 @@ $model->generateLangs(); if ($model->load(Yii::$app->request->post())) { $model->loadLangs(\Yii::$app->request); - // TaxOption::find() - // ->rebuildMP($model->tax_group_id); if ($model->save() && $model->transactionStatus) { return $this->redirect( [ diff --git a/common/modules/rubrication/models/TaxGroup.php b/common/modules/rubrication/models/TaxGroup.php index c6b1703..6143966 100755 --- a/common/modules/rubrication/models/TaxGroup.php +++ b/common/modules/rubrication/models/TaxGroup.php @@ -5,6 +5,7 @@ use common\modules\language\behaviors\LanguageBehavior; use common\modules\language\models\Language; use common\modules\product\models\Category; + use yii\base\InvalidValueException; use yii\db\ActiveQuery; use yii\db\ActiveRecord; use yii\web\Request; @@ -22,6 +23,8 @@ * @property TaxOption[] $taxOptions * @property Category[] $categories * @property TaxOption[] $options + * @property TaxOption[] $customOptions + * @property string $alias * * From language behavior * * @property TaxGroupLang $lang * @property TaxGroupLang[] $langs @@ -52,7 +55,7 @@ /** * @var TaxOption[] $options */ - public $options = []; + protected $customOptions = []; /** * @inheritdoc @@ -116,17 +119,28 @@ ]; } + /** + * @return ActiveQuery + */ public function getCategories() { return $this->hasMany(Category::className(), [ 'id' => 'category_id' ]) ->viaTable('tax_group_to_category', [ 'tax_group_id' => 'id' ]); } - public function setCategories($values) + /** + * Set categories to override tax_group_to_category table data + * + * @param int[] $values + */ + public function setCategories(array $values) { $this->categories = $values; } + /** + * @inheritdoc + */ public function afterSave($insert, $changedAttributes) { parent::afterSave($insert, $changedAttributes); @@ -141,6 +155,18 @@ } /** + * @return ActiveQuery + */ + public function getTaxOptions() + { + return $this->hasMany(TaxOption::className(), [ 'tax_group_id' => 'id' ]) + ->inverseOf('taxGroup'); + } + + /** + * Synonim for getTaxOptions() + * + * @see TaxGroup::getTaxOptions() * @return \yii\db\ActiveQuery */ public function getOptions() @@ -148,12 +174,44 @@ return $this->getTaxOptions(); } - public function getTaxOptions() + /** + * Get customOptins that were filled dynamically. + * If $fillDefault is true then fill $customOptions with TaxOptions for current TaxGroup + * + * @param bool $fillDefault + * + * @return TaxOption[] + */ + public function getCustomOptions(bool $fillDefault = false): array { - return $this->hasMany(TaxOption::className(), [ 'tax_group_id' => 'id' ]) - ->inverseOf('taxGroup'); + if ($fillDefault && empty( $this->custom_options )) { + $this->customOptions = $this->getTaxOptions() + ->with('lang') + ->all(); + } + return $this->customOptions; + } + + /** + * Set customOptions + * + * @param TaxOption[] $value + */ + public function setCustomOptions(array $value) + { + foreach ($value as $item) { + if (!( $item instanceof TaxOption )) { + throw new InvalidValueException('All elements must be instances of ' . TaxOption::className()); + } + } + $this->customOptions = $value; } + /** + * Get default lang alias + * + * @return string + */ public function getAlias() { $default_lang = Language::getDefaultLanguage(); diff --git a/common/modules/rubrication/models/TaxOption.php b/common/modules/rubrication/models/TaxOption.php index 0770813..6df7442 100755 --- a/common/modules/rubrication/models/TaxOption.php +++ b/common/modules/rubrication/models/TaxOption.php @@ -20,6 +20,7 @@ * @property integer $sort * @property string $image * @property TaxGroup $taxGroup + * @property TaxGroup $group * @property Product[] $products * @property ProductVariant[] $productVariants * * From language behavior * @@ -52,8 +53,6 @@ class TaxOption extends ActiveRecord { - public $itemsCount; - /** * @inheritdoc */ @@ -122,26 +121,35 @@ /** * @return \yii\db\ActiveQuery */ - public function getGroup() + public function getTaxGroup() { - return $this->getTaxGroup(); + return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) + ->inverseOf('taxOptions'); } /** + * Synonim for TaxOption::getTaxGroup() + * + * @see TaxOption::getTaxGroup() * @return \yii\db\ActiveQuery */ - public function getTaxGroup() + public function getGroup() { - return $this->hasOne(TaxGroup::className(), [ 'id' => 'tax_group_id' ]) - ->inverseOf('taxOptions'); + return $this->getTaxGroup(); } + /** + * @return ActiveQuery + */ public function getProducts() { return $this->hasMany(Product::className(), [ 'id' => 'product_id' ]) ->viaTable('product_option', [ 'option_id' => 'id' ]); } + /** + * @return ActiveQuery + */ public function getProductVariants() { return $this->hasMany(ProductVariant::className(), [ 'id' => 'product_variant_id' ]) diff --git a/common/modules/rubrication/models/TaxOptionQuery.php b/common/modules/rubrication/models/TaxOptionQuery.php deleted file mode 100755 index f37c92d..0000000 --- a/common/modules/rubrication/models/TaxOptionQuery.php +++ /dev/null @@ -1,34 +0,0 @@ -