From a5a111148412fbadb4b96b4d32e4c0b2cb7ae61f Mon Sep 17 00:00:00 2001 From: jitendra Date: Thu, 7 Jul 2022 17:19:32 +0530 Subject: [PATCH] Product system performance optimization --- .../src/Repositories/AttributeRepository.php | 17 +++ .../Webkul/CartRule/src/Helpers/CartRule.php | 4 + packages/Webkul/Checkout/src/Cart.php | 40 +++++- .../src/Providers/CheckoutServiceProvider.php | 2 +- .../Checkout/src/Traits/CartCoupons.php | 4 + .../Webkul/Checkout/src/Traits/CartTools.php | 4 + .../src/Helpers/ConfigurableOption.php | 10 +- .../Http/Controllers/ProductController.php | 28 +--- .../Product/src/Listeners/ProductFlat.php | 120 +++++++++------- .../Webkul/Product/src/Models/Product.php | 18 ++- .../Webkul/Product/src/Models/ProductFlat.php | 25 +--- .../ProductAttributeValueRepository.php | 36 ----- .../src/Repositories/ProductRepository.php | 2 +- .../Webkul/Product/src/Type/AbstractType.php | 88 +++++++++--- .../Webkul/Product/src/Type/Configurable.php | 136 ++++++++++++------ 15 files changed, 314 insertions(+), 220 deletions(-) diff --git a/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php b/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php index 883dca91f..0892ad78a 100755 --- a/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php +++ b/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php @@ -206,6 +206,23 @@ class AttributeRepository extends Repository return $attributes[$code] = $this->findOneByField('code', $code); } + /** + * Get attribute by id. + * + * @param integer $id + * @return \Webkul\Attribute\Contracts\Attribute + */ + public function getAttributeById($id) + { + static $attributes = []; + + if (array_key_exists($id, $attributes)) { + return $attributes[$id]; + } + + return $attributes[$id] = $this->find($id); + } + /** * Get family attributes. * diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index 52b36e100..8837e64a9 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -367,6 +367,8 @@ class CartRule $cart->save(); + Cart::setCart($cart); + return $this; } @@ -430,6 +432,8 @@ class CartRule $cart->applied_cart_rule_ids = join(',', $cartAppliedCartRuleIds); $cart->save(); + + Cart::setCart($cart); } /** diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php index 3603fb67f..3c9bfe353 100755 --- a/packages/Webkul/Checkout/src/Cart.php +++ b/packages/Webkul/Checkout/src/Cart.php @@ -49,6 +49,7 @@ class Cart { } + protected $cart; /** * Returns cart. * @@ -56,20 +57,31 @@ class Cart */ public function getCart(): ?\Webkul\Checkout\Contracts\Cart { - $cart = null; + if ($this->cart) { + return $this->cart; + } if (auth()->guard()->check()) { - $cart = $this->cartRepository->findOneWhere([ + $this->cart = $this->cartRepository->findOneWhere([ 'customer_id' => auth()->guard()->user()->id, 'is_active' => 1, ]); } else if (session()->has('cart')) { - $cart = $this->cartRepository->find(session()->get('cart')->id); + $this->cart = $this->cartRepository->find(session()->get('cart')->id); } - $this->removeInactiveItems($cart); + $this->removeInactiveItems($this->cart); - return $cart; + return $this->cart; + } + /** + * Returns cart. + * + * @return \Webkul\Checkout\Contracts\Cart|null + */ + public function setCart($cart) + { + $this->cart = $cart; } /** @@ -158,6 +170,8 @@ class Cart } } + $this->setCart($cart); + Event::dispatch('checkout.cart.add.after', $cart); $this->collectTotals(); @@ -280,6 +294,8 @@ class Cart if (session()->has('cart')) { session()->forget('cart'); } + + $this->setCart(null); } Shipping::collectRates(); @@ -313,7 +329,9 @@ class Cart $this->removeItem($item->id); } - Event::dispatch('checkout.cart.delete.all.after', $cart); + $this->setCart(null); + + Event::dispatch('checkout.cart.delete.all.after', null); return $cart; } @@ -341,6 +359,8 @@ class Cart if (session()->has('cart')) { session()->forget('cart'); } + + $this->setCart(null); } session()->flash('info', __('shop::app.checkout.cart.item.inactive')); @@ -377,6 +397,8 @@ class Cart $cart->save(); + $this->setCart($cart); + $this->collectTotals(); return true; @@ -401,6 +423,8 @@ class Cart $cart->shipping_method = $shippingMethodCode; $cart->save(); + $this->setCart($cart); + return true; } @@ -492,6 +516,8 @@ class Cart $cart->save(); + $this->setCart($cart); + Event::dispatch('checkout.cart.collect.totals.after', $cart); } @@ -543,6 +569,8 @@ class Cart $item->save(); } + $this->setCart($cart); + Event::dispatch('checkout.cart.calculate.items.tax.after', $cart); } diff --git a/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php b/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php index e9233568c..408ac0860 100755 --- a/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php +++ b/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php @@ -49,6 +49,6 @@ class CheckoutServiceProvider extends ServiceProvider return new Cart(); }); - $this->app->bind('cart', \Webkul\Checkout\Cart::class); + $this->app->singleton('cart', \Webkul\Checkout\Cart::class); } } diff --git a/packages/Webkul/Checkout/src/Traits/CartCoupons.php b/packages/Webkul/Checkout/src/Traits/CartCoupons.php index a1c079292..d2aba17ae 100644 --- a/packages/Webkul/Checkout/src/Traits/CartCoupons.php +++ b/packages/Webkul/Checkout/src/Traits/CartCoupons.php @@ -25,6 +25,8 @@ trait CartCoupons $cart->save(); + $this->setCart($cart); + return $this; } @@ -41,6 +43,8 @@ trait CartCoupons $cart->save(); + $this->setCart($cart); + return $this; } } \ No newline at end of file diff --git a/packages/Webkul/Checkout/src/Traits/CartTools.php b/packages/Webkul/Checkout/src/Traits/CartTools.php index 6008696de..bc45e3978 100644 --- a/packages/Webkul/Checkout/src/Traits/CartTools.php +++ b/packages/Webkul/Checkout/src/Traits/CartTools.php @@ -68,6 +68,8 @@ trait CartTools $this->cartRepository->delete($guestCart->id); + $this->setCart($cart); + session()->forget('cart'); } } @@ -239,6 +241,8 @@ trait CartTools if (! $cart->items->count()) { $this->cartRepository->delete($cart->id); + + $this->setCart(null); } $this->collectTotals(); diff --git a/packages/Webkul/Product/src/Helpers/ConfigurableOption.php b/packages/Webkul/Product/src/Helpers/ConfigurableOption.php index deb184407..183b43486 100755 --- a/packages/Webkul/Product/src/Helpers/ConfigurableOption.php +++ b/packages/Webkul/Product/src/Helpers/ConfigurableOption.php @@ -55,12 +55,18 @@ class ConfigurableOption extends AbstractProduct /** * Get allowed attributes. * - * @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product + * @param \W\Webkul\Product\Contracts\ProductFlat $product * @return \Illuminate\Support\Collection */ public function getAllowAttributes($product) { - return $product->product->super_attributes; + static $productSuperAttributes = []; + + if (isset($productSuperAttributes[$product->id])) { + return $productSuperAttributes[$product->id]; + } + + return $productSuperAttributes[$product->id] = $product->product->super_attributes()->with(['translation', 'options', 'options.translation'])->get(); } /** diff --git a/packages/Webkul/Product/src/Http/Controllers/ProductController.php b/packages/Webkul/Product/src/Http/Controllers/ProductController.php index a7f6a5121..25da17866 100755 --- a/packages/Webkul/Product/src/Http/Controllers/ProductController.php +++ b/packages/Webkul/Product/src/Http/Controllers/ProductController.php @@ -151,33 +151,7 @@ class ProductController extends Controller */ public function update(ProductForm $request, $id) { - $data = request()->all(); - - $multiselectAttributeCodes = []; - - $productAttributes = $this->productRepository->findOrFail($id); - - foreach ($productAttributes->attribute_family->attribute_groups as $attributeGroup) { - $customAttributes = $productAttributes->getEditableAttributes($attributeGroup); - - if (count($customAttributes)) { - foreach ($customAttributes as $attribute) { - if ($attribute->type == 'multiselect' || $attribute->type == 'checkbox') { - array_push($multiselectAttributeCodes, $attribute->code); - } - } - } - } - - if (count($multiselectAttributeCodes)) { - foreach ($multiselectAttributeCodes as $multiselectAttributeCode) { - if (! isset($data[$multiselectAttributeCode])) { - $data[$multiselectAttributeCode] = []; - } - } - } - - $this->productRepository->update($data, $id); + $this->productRepository->update(request()->all(), $id); session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Product'])); diff --git a/packages/Webkul/Product/src/Listeners/ProductFlat.php b/packages/Webkul/Product/src/Listeners/ProductFlat.php index 029fa086d..2528df611 100644 --- a/packages/Webkul/Product/src/Listeners/ProductFlat.php +++ b/packages/Webkul/Product/src/Listeners/ProductFlat.php @@ -13,13 +13,6 @@ use Webkul\Product\Models\ProductAttributeValue; class ProductFlat { - /** - * Attribute Object - * - * @var \Webkul\Attribute\Contracts\Attribute - */ - protected $attribute; - /** * Attribute codes that can be fill during flat creation. * @@ -50,6 +43,11 @@ class ProductFlat 'checkbox' => 'text', ]; + /** + * @var array + */ + protected $flatColumns = []; + /** * Create a new listener instance. * @@ -66,6 +64,7 @@ class ProductFlat protected ProductAttributeValueRepository $productAttributeValueRepository ) { + $this->flatColumns = Schema::getColumnListing('product_flat'); } /** @@ -82,10 +81,11 @@ class ProductFlat if (! $attribute->use_in_flat) { $this->afterAttributeDeleted($attribute->id); + return false; } - if (! Schema::hasColumn('product_flat', $attribute->code)) { + if (! in_array($attribute->code, $this->flatColumns)) { Schema::table('product_flat', function (Blueprint $table) use($attribute) { $table->{$this->attributeTypeFields[$attribute->type]}($attribute->code)->nullable(); @@ -105,8 +105,8 @@ class ProductFlat public function afterAttributeDeleted($attributeId) { $attribute = $this->attributeRepository->find($attributeId); - - if (Schema::hasColumn('product_flat', strtolower($attribute->code))) { + + if (in_array(strtolower($attribute->code), $this->flatColumns)) { Schema::table('product_flat', function (Blueprint $table) use($attribute) { $table->dropColumn($attribute->code); @@ -115,7 +115,7 @@ class ProductFlat } }); - $this->productFlatRepository->updateAttributeColumn( $attribute , $this ); + $this->productFlatRepository->updateAttributeColumn( $attribute , $this); } } @@ -150,8 +150,8 @@ class ProductFlat static $superAttributes = []; - if (! array_key_exists($product->attribute_family->id, $familyAttributes)) { - $familyAttributes[$product->attribute_family->id] = $product->attribute_family->custom_attributes; + if (! array_key_exists($product->attribute_family_id, $familyAttributes)) { + $familyAttributes[$product->attribute_family_id] = $product->attribute_family->custom_attributes; } if ($parentProduct && ! array_key_exists($parentProduct->id, $superAttributes)) { @@ -161,72 +161,69 @@ class ProductFlat if (isset($product['channels'])) { foreach ($product['channels'] as $channel) { $channel = app('Webkul\Core\Repositories\ChannelRepository')->findOrFail($channel); + $channels[] = $channel['code']; } - } elseif (isset($parentProduct['channels'])){ + } else if (isset($parentProduct['channels'])){ foreach ($parentProduct['channels'] as $channel) { $channel = app('Webkul\Core\Repositories\ChannelRepository')->findOrFail($channel); + $channels[] = $channel['code']; } } else { $channels[] = core()->getDefaultChannelCode(); } + $attributeValues = $product->attribute_values()->get(); + foreach (core()->getAllChannels() as $channel) { if (in_array($channel->code, $channels)) { foreach ($channel->locales as $locale) { - $productFlat = $this->productFlatRepository->findOneWhere([ + $productFlat = $this->productFlatRepository->updateOrCreate([ 'product_id' => $product->id, 'channel' => $channel->code, 'locale' => $locale->code, ]); - if (! $productFlat) { - $productFlat = $this->productFlatRepository->create([ - 'product_id' => $product->id, - 'channel' => $channel->code, - 'locale' => $locale->code, - ]); - } - - foreach ($familyAttributes[$product->attribute_family->id] as $attribute) { - if ($parentProduct && ! in_array($attribute->code, array_merge($superAttributes[$parentProduct->id], $this->fillableAttributeCodes))) { - continue; - } - - if (in_array($attribute->code, ['tax_category_id'])) { - continue; - } - - if (! Schema::hasColumn('product_flat', $attribute->code)) { + foreach ($familyAttributes[$product->attribute_family_id] as $attribute) { + if (($parentProduct + && ! in_array($attribute->code, array_merge($superAttributes[$parentProduct->id], $this->fillableAttributeCodes))) + || in_array($attribute->code, ['tax_category_id']) + || ! in_array($attribute->code, $this->flatColumns) + ) { continue; } if ($attribute->value_per_channel) { if ($attribute->value_per_locale) { - $productAttributeValue = $product->attribute_values() - ->where('channel', $channel->code) - ->where('locale', $locale->code) - ->where('attribute_id', $attribute->id) - ->first(); + $productAttributeValue = $attributeValues + ->where('channel', $channel->code) + ->where('locale', $locale->code) + ->where('attribute_id', $attribute->id) + ->first(); } else { - $productAttributeValue = $product->attribute_values() - ->where('channel', $channel->code) - ->where('attribute_id', $attribute->id) - ->first(); + $productAttributeValue = $attributeValues + ->where('channel', $channel->code) + ->where('attribute_id', $attribute->id) + ->first(); } } else { if ($attribute->value_per_locale) { - $productAttributeValue = $product->attribute_values()->where('locale', $locale->code)->where('attribute_id', $attribute->id)->first(); + $productAttributeValue = $attributeValues + ->where('locale', $locale->code) + ->where('attribute_id', $attribute->id) + ->first(); } else { - $productAttributeValue = $product->attribute_values()->where('attribute_id', $attribute->id)->first(); + $productAttributeValue = $attributeValues + ->where('attribute_id', $attribute->id) + ->first(); } } $productFlat->{$attribute->code} = $productAttributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]] ?? null; if ($attribute->type == 'select') { - $attributeOption = $this->attributeOptionRepository->find($product->{$attribute->code}); + $attributeOption = $this->getAttributeOptions($productFlat->{$attribute->code}); if ($attributeOption) { if ($attributeOptionTranslation = $attributeOption->translate($locale->code)) { @@ -236,10 +233,10 @@ class ProductFlat } } } elseif ($attribute->type == 'multiselect') { - $attributeOptionIds = explode(',', $product->{$attribute->code}); + $attributeOptionIds = explode(',', $productFlat->{$attribute->code}); if (count($attributeOptionIds)) { - $attributeOptions = $this->attributeOptionRepository->findWhereIn('id', $attributeOptionIds); + $attributeOptions = $this->getAttributeOptions($productFlat->{$attribute->code}); $optionLabels = []; @@ -256,10 +253,6 @@ class ProductFlat } } - $productFlat->created_at = $product->created_at; - - $productFlat->updated_at = $product->updated_at; - $productFlat->min_price = $product->getTypeInstance()->getMinimalPrice(); $productFlat->max_price = $product->getTypeInstance()->getMaximamPrice(); @@ -294,4 +287,29 @@ class ProductFlat } } } + + /** + * @param string $value + * @return mixed + */ + public function getAttributeOptions($value) + { + if (! $value) { + return; + } + + static $attributeOptions = []; + + if (array_key_exists($value, $attributeOptions)) { + return $attributeOptions[$value]; + } + + if (is_numeric($value)) { + return $attributeOptions[$value] = $this->attributeOptionRepository->find($value); + } else { + $attributeOptionIds = explode(',', $value); + + return $attributeOptions[$value] = $this->attributeOptionRepository->findWhereIn('id', $attributeOptionIds); + } + } } diff --git a/packages/Webkul/Product/src/Models/Product.php b/packages/Webkul/Product/src/Models/Product.php index 799da8146..98b61c31f 100755 --- a/packages/Webkul/Product/src/Models/Product.php +++ b/packages/Webkul/Product/src/Models/Product.php @@ -441,19 +441,17 @@ class Product extends Model implements ProductContract */ public function getAttribute($key) { + if (! method_exists(static::class, $key) && ! in_array($key, [ 'pivot', 'parent_id', 'attribute_family_id', ]) - && ! isset($this->attributes[$key])) { + && ! isset($this->attributes[$key]) + ) { if (isset($this->id)) { - $this->attributes[$key] = ''; - - $attribute = core() - ->getSingletonInstance(AttributeRepository::class) - ->getAttributeByCode($key); + $attribute = $this->checkInLoadedFamilyAttributes()->where('code', $key)->first(); $this->attributes[$key] = $this->getCustomAttributeValue($attribute); @@ -500,25 +498,25 @@ class Product extends Model implements ProductContract if ($attribute->value_per_channel) { if ($attribute->value_per_locale) { - $attributeValue = $this->attribute_values() + $attributeValue = $this->attribute_values ->where('channel', $channel) ->where('locale', $locale) ->where('attribute_id', $attribute->id) ->first(); } else { - $attributeValue = $this->attribute_values() + $attributeValue = $this->attribute_values ->where('channel', $channel) ->where('attribute_id', $attribute->id) ->first(); } } else { if ($attribute->value_per_locale) { - $attributeValue = $this->attribute_values() + $attributeValue = $this->attribute_values ->where('locale', $locale) ->where('attribute_id', $attribute->id) ->first(); } else { - $attributeValue = $this->attribute_values() + $attributeValue = $this->attribute_values ->where('attribute_id', $attribute->id) ->first(); } diff --git a/packages/Webkul/Product/src/Models/ProductFlat.php b/packages/Webkul/Product/src/Models/ProductFlat.php index e727e2da9..38c88b797 100644 --- a/packages/Webkul/Product/src/Models/ProductFlat.php +++ b/packages/Webkul/Product/src/Models/ProductFlat.php @@ -45,7 +45,7 @@ class ProductFlat extends Model implements ProductFlatContract * * @var boolean */ - public $timestamps = false; + // public $timestamps = false; /** * Get the index name for the model. @@ -137,16 +137,6 @@ class ProductFlat extends Model implements ProductFlatContract return $this->hasMany(static::class, 'parent_id'); } - /** - * Get all of the attributes for the attribute groups. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getImagesAttribute() - { - return $this->images()->get(); - } - /** * The images that belong to the product. * @@ -165,18 +155,7 @@ class ProductFlat extends Model implements ProductFlatContract */ public function videos() { - return $this->product->videos() - ->orderBy('position'); - } - - /** - * Get all of the reviews for the attribute groups. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getReviewsAttribute() - { - return $this->reviews()->get(); + return $this->product->videos()->orderBy('position'); } /** diff --git a/packages/Webkul/Product/src/Repositories/ProductAttributeValueRepository.php b/packages/Webkul/Product/src/Repositories/ProductAttributeValueRepository.php index 594e668c0..b46df6edc 100755 --- a/packages/Webkul/Product/src/Repositories/ProductAttributeValueRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductAttributeValueRepository.php @@ -9,21 +9,6 @@ use Webkul\Product\Models\ProductAttributeValueProxy; class ProductAttributeValueRepository extends Repository { - /** - * Create a new reposotory instance. - * - * @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository - * @param \Illuminate\Container\Container $app - * @return void - */ - public function __construct( - protected AttributeRepository $attributeRepository, - App $app - ) - { - parent::__construct($app); - } - /** * Specify Model class name * @@ -34,27 +19,6 @@ class ProductAttributeValueRepository extends Repository return 'Webkul\Product\Contracts\ProductAttributeValue'; } - /** - * @param array $data - * @return \Webkul\Product\Contracts\ProductAttributeValue - */ - public function create(array $data) - { - if (isset($data['attribute_id'])) { - $attribute = $this->attributeRepository->find($data['attribute_id']); - } else { - $attribute = $this->attributeRepository->findOneByField('code', $data['attribute_code']); - } - - if (! $attribute) { - return; - } - - $data[ProductAttributeValueProxy::modelClass()::$attributeTypeFields[$attribute->type]] = $data['value']; - - return $this->model->create($data); - } - /** * @param string $column * @param int $attributeId diff --git a/packages/Webkul/Product/src/Repositories/ProductRepository.php b/packages/Webkul/Product/src/Repositories/ProductRepository.php index dc2bc0f7c..4f7a420de 100755 --- a/packages/Webkul/Product/src/Repositories/ProductRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductRepository.php @@ -77,7 +77,7 @@ class ProductRepository extends Repository { Event::dispatch('catalog.product.update.before', $id); - $product = $this->find($id); + $product = $this->findOrFail($id); $product = $product->getTypeInstance()->update($data, $id, $attribute); diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index e8dbdbc89..c24f33f42 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -177,6 +177,10 @@ abstract class AbstractType $data[$attribute->code] = isset($data[$attribute->code]) && $data[$attribute->code] ? 1 : 0; } + if ($attribute->type == 'multiselect' || $attribute->type == 'checkbox') { + $data[$attribute->code] = isset($data[$attribute->code]) ? implode(',', $data[$attribute->code]) : null; + } + if (! isset($data[$attribute->code])) { continue; } @@ -189,38 +193,50 @@ abstract class AbstractType $data[$attribute->code] = null; } - if ($attribute->type === 'multiselect' || $attribute->type === 'checkbox') { - $data[$attribute->code] = implode(',', $data[$attribute->code]); - } - if ($attribute->type === 'image' || $attribute->type === 'file') { $data[$attribute->code] = gettype($data[$attribute->code]) === 'object' ? request()->file($attribute->code)->store('product/' . $product->id) : null; } - $attributeValue = $this->attributeValueRepository->findOneWhere([ - 'product_id' => $product->id, - 'attribute_id' => $attribute->id, - 'channel' => $attribute->value_per_channel ? $data['channel'] : null, - 'locale' => $attribute->value_per_locale ? $data['locale'] : null, - ]); + if ($attribute->value_per_channel) { + if ($attribute->value_per_locale) { + $productAttributeValue = $product->attribute_values + ->where('channel', $attribute->value_per_channel ? $data['channel'] : null) + ->where('locale', $attribute->value_per_locale ? $data['locale'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } else { + $productAttributeValue = $product->attribute_values + ->where('channel', $attribute->value_per_channel ? $data['channel'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } + } else { + if ($attribute->value_per_locale) { + $productAttributeValue = $product->attribute_values + ->where('locale', $attribute->value_per_locale ? $data['locale'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } else { + $productAttributeValue = $product->attribute_values + ->where('attribute_id', $attribute->id) + ->first(); + } + } - if (! $attributeValue) { + $columnName = ProductAttributeValue::$attributeTypeFields[$attribute->type]; + + if (! $productAttributeValue) { $this->attributeValueRepository->create([ 'product_id' => $product->id, 'attribute_id' => $attribute->id, - 'value' => $data[$attribute->code], + $columnName => $data[$attribute->code], 'channel' => $attribute->value_per_channel ? $data['channel'] : null, 'locale' => $attribute->value_per_locale ? $data['locale'] : null, ]); } else { - $this->attributeValueRepository->update( - [ - ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code], - ], - $attributeValue->id - ); + $productAttributeValue->update([$columnName => $data[$attribute->code]]); if ($attribute->type == 'image' || $attribute->type == 'file') { Storage::delete($attributeValue->text_value); @@ -271,6 +287,28 @@ abstract class AbstractType return $this; } + /** + * @param string $code + * @return mixed + */ + public function getAttributeByCode($code) + { + return core() + ->getSingletonInstance(AttributeRepository::class) + ->getAttributeByCode($code); + } + + /** + * @param integer $id + * @return mixed + */ + public function getAttributeById($id) + { + return core() + ->getSingletonInstance(AttributeRepository::class) + ->getAttributeById($id); + } + /** * Returns children ids. * @@ -413,7 +451,7 @@ abstract class AbstractType } } - $orderedInventory = $this->product->ordered_inventories() + $orderedInventory = $this->product->ordered_inventories ->where('channel_id', core()->getCurrentChannel()->id)->first(); if ($orderedInventory) { @@ -535,6 +573,12 @@ abstract class AbstractType */ public function haveSpecialPrice($qty = null) { + static $haveSpecialPrice = null; + + if (! is_null($haveSpecialPrice)) { + return $haveSpecialPrice; + } + $customerGroupPrice = $this->getCustomerGroupPrice($this->product, $qty); $rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product); @@ -715,7 +759,7 @@ abstract class AbstractType if ($taxCategory = $this->getTaxCategory()) { if ($address === null && auth()->guard('customer')->check()) { - $address = auth()->guard('customer')->user()->addresses()->where('default_address', 1)->first(); + $address = auth()->guard('customer')->user()->addresses->where('default_address', 1)->first(); } if ($address === null) { @@ -959,9 +1003,7 @@ abstract class AbstractType if (auth()->guard()->check()) { $customerGroupId = auth()->guard()->user()->customer_group_id; } else { - $customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository'); - - if ($customerGuestGroup = $customerGroupRepository->findOneByField('code', 'guest')) { + if ($customerGuestGroup = app(CustomerGroupRepository::class)->findOneByField('code', 'guest')) { $customerGroupId = $customerGuestGroup->id; } } diff --git a/packages/Webkul/Product/src/Type/Configurable.php b/packages/Webkul/Product/src/Type/Configurable.php index 580981514..27cd21d9d 100644 --- a/packages/Webkul/Product/src/Type/Configurable.php +++ b/packages/Webkul/Product/src/Type/Configurable.php @@ -129,7 +129,7 @@ class Configurable extends AbstractType $super_attributes = []; foreach ($data['super_attributes'] as $attributeCode => $attributeOptions) { - $attribute = $this->attributeRepository->findOneByField('code', $attributeCode); + $attribute = $this->getAttributeByCode($attributeCode); $super_attributes[$attribute->id] = $attributeOptions; @@ -233,69 +233,92 @@ class Configurable extends AbstractType 'sku' => $data['sku'], ]); + $attributeValues = []; + foreach ($this->fillableTypes as $attributeCode) { if (! isset($data[$attributeCode])) { continue; } - $attribute = $this->attributeRepository->findOneByField('code', $attributeCode); + $attribute = $this->getAttributeByCode($attributeCode); + + $attributeTypeFields = $this->getAttributeTypeValues($attribute->type, $data[$attributeCode]); if ($attribute->value_per_channel) { if ($attribute->value_per_locale) { foreach (core()->getAllChannels() as $channel) { foreach (core()->getAllLocales() as $locale) { - $this->attributeValueRepository->create([ + $attributeValues[] = array_merge($attributeTypeFields, [ 'product_id' => $variant->id, 'attribute_id' => $attribute->id, 'channel' => $channel->code, 'locale' => $locale->code, - 'value' => $data[$attributeCode], ]); } } } else { foreach (core()->getAllChannels() as $channel) { - $this->attributeValueRepository->create([ + $attributeValues[] = array_merge($attributeTypeFields, [ 'product_id' => $variant->id, 'attribute_id' => $attribute->id, 'channel' => $channel->code, - 'value' => $data[$attributeCode], + 'locale' => null, ]); } } } else { if ($attribute->value_per_locale) { foreach (core()->getAllLocales() as $locale) { - $this->attributeValueRepository->create([ + $attributeValues[] = array_merge($attributeTypeFields, [ 'product_id' => $variant->id, 'attribute_id' => $attribute->id, + 'channel' => null, 'locale' => $locale->code, - 'value' => $data[$attributeCode], ]); } } else { - $this->attributeValueRepository->create([ + $attributeValues[] = array_merge($attributeTypeFields, [ 'product_id' => $variant->id, 'attribute_id' => $attribute->id, - 'value' => $data[$attributeCode], + 'channel' => null, + 'locale' => null, ]); } } } foreach ($permutation as $attributeId => $optionId) { - $this->attributeValueRepository->create([ + $attribute = $this->getAttributeById($attributeId); + + $attributeValues[] = array_merge($this->getAttributeTypeValues($attribute->type, $optionId), [ 'product_id' => $variant->id, 'attribute_id' => $attributeId, - 'value' => $optionId, + 'channel' => null, + 'locale' => null, ]); } + $this->attributeValueRepository->insert($attributeValues); + $this->productInventoryRepository->saveInventories($data, $variant); return $variant; } + /** + * @param string $attributeType + * @param mixed $value + * @return array + */ + public function getAttributeTypeValues($attributeType, $value) + { + $attributeTypeFields = array_fill_keys(array_values(ProductAttributeValue::$attributeTypeFields), null); + + $attributeTypeFields[ProductAttributeValue::$attributeTypeFields[$attributeType]] = $value; + + return $attributeTypeFields; + } + /** * Update variant. * @@ -314,27 +337,46 @@ class Configurable extends AbstractType continue; } - $attribute = $this->attributeRepository->findOneByField('code', $attributeCode); + $attribute = $this->getAttributeByCode($attributeCode); - $attributeValue = $this->attributeValueRepository->findOneWhere([ - 'product_id' => $id, - 'attribute_id' => $attribute->id, - 'channel' => $attribute->value_per_channel ? $data['channel'] : null, - 'locale' => $attribute->value_per_locale ? $data['locale'] : null, - ]); + if ($attribute->value_per_channel) { + if ($attribute->value_per_locale) { + $productAttributeValue = $variant->attribute_values + ->where('channel', $attribute->value_per_channel ? $data['channel'] : null) + ->where('locale', $attribute->value_per_locale ? $data['locale'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } else { + $productAttributeValue = $variant->attribute_values + ->where('channel', $attribute->value_per_channel ? $data['channel'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } + } else { + if ($attribute->value_per_locale) { + $productAttributeValue = $variant->attribute_values + ->where('locale', $attribute->value_per_locale ? $data['locale'] : null) + ->where('attribute_id', $attribute->id) + ->first(); + } else { + $productAttributeValue = $variant->attribute_values + ->where('attribute_id', $attribute->id) + ->first(); + } + } - if (! $attributeValue) { + $columnName = ProductAttributeValue::$attributeTypeFields[$attribute->type]; + + if (! $productAttributeValue) { $this->attributeValueRepository->create([ - 'product_id' => $id, + 'product_id' => $variant->id, 'attribute_id' => $attribute->id, - 'value' => $data[$attribute->code], + $columnName => $data[$attribute->code], 'channel' => $attribute->value_per_channel ? $data['channel'] : null, 'locale' => $attribute->value_per_locale ? $data['locale'] : null, ]); } else { - $this->attributeValueRepository->update([ - ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code], - ], $attributeValue->id); + $productAttributeValue->update([$columnName => $data[$attribute->code]]); } } @@ -457,7 +499,11 @@ class Configurable extends AbstractType */ public function getMinimalPrice($qty = null) { - $minPrices = []; + static $minPrice = null; + + if (! is_null($minPrice)) { + return $minPrice; + } /* method is calling many time so using variable */ $tablePrefix = DB::getTablePrefix(); @@ -471,6 +517,9 @@ class Configurable extends AbstractType ->where('product_flat.channel', core()->getCurrentChannelCode()) ->get(); + + $minPrices = []; + foreach ($result as $price) { $minPrices[] = $price->min_price; } @@ -479,7 +528,7 @@ class Configurable extends AbstractType return 0; } - return min($minPrices); + return $minPrice = min($minPrices); } /** @@ -489,6 +538,12 @@ class Configurable extends AbstractType */ public function getOfferPrice() { + static $offerPrice = null; + + if (! is_null($offerPrice)) { + return $offerPrice; + } + $rulePrices = $customerGroupPrices = []; foreach ($this->product->variants as $variant) { @@ -502,10 +557,10 @@ class Configurable extends AbstractType } if ($rulePrices || $customerGroupPrices) { - return min(array_merge($rulePrices, $customerGroupPrices)); + return $offerPrice = min(array_merge($rulePrices, $customerGroupPrices)); } - return []; + return $offerPrice = []; } /** @@ -515,16 +570,11 @@ class Configurable extends AbstractType */ public function haveOffer() { - $haveOffer = false; - - $offerPrice = $this->getOfferPrice(); - $minPrice = $this->getMinimalPrice(); - - if ($offerPrice < $minPrice) { - $haveOffer = true; + if ($this->getOfferPrice() < $this->getMinimalPrice()) { + return true; } - return $haveOffer; + return false; } /** @@ -534,6 +584,12 @@ class Configurable extends AbstractType */ public function getMaximamPrice() { + static $maxPrice = null; + + if (! is_null($maxPrice)) { + return $maxPrice; + } + $productFlat = ProductFlat::join('products', 'product_flat.product_id', '=', 'products.id') ->distinct() ->where('products.parent_id', $this->product->id) @@ -542,7 +598,7 @@ class Configurable extends AbstractType ->where('product_flat.locale', app()->getLocale()) ->first(); - return $productFlat ? $productFlat->max_price : 0; + return $maxPrice = $productFlat ? $productFlat->max_price : 0; } /** @@ -823,7 +879,7 @@ class Configurable extends AbstractType $total = 0; $channelInventorySourceIds = core()->getCurrentChannel() - ->inventory_sources() + ->inventory_sources ->where('status', 1) ->pluck('id'); @@ -834,7 +890,7 @@ class Configurable extends AbstractType } } - $orderedInventory = $variant->ordered_inventories() + $orderedInventory = $variant->ordered_inventories ->where('channel_id', core()->getCurrentChannel()->id) ->first();