diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index 27b4fc2c7..c88d53d14 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -3,15 +3,15 @@ namespace Webkul\CartRule\Helpers; use Carbon\Carbon; +use Webkul\Checkout\Facades\Cart; +use Webkul\Rule\Helpers\Validator; +use Webkul\Checkout\Models\CartItem; use Illuminate\Database\Eloquent\Builder; use Webkul\CartRule\Repositories\CartRuleRepository; -use Webkul\CartRule\Repositories\CartRuleCouponRepository; -use Webkul\CartRule\Repositories\CartRuleCouponUsageRepository; -use Webkul\CartRule\Repositories\CartRuleCustomerRepository; use Webkul\Customer\Repositories\CustomerGroupRepository; -use Webkul\Checkout\Models\CartItem; -use Webkul\Rule\Helpers\Validator; -use Webkul\Checkout\Facades\Cart; +use Webkul\CartRule\Repositories\CartRuleCouponRepository; +use Webkul\CartRule\Repositories\CartRuleCustomerRepository; +use Webkul\CartRule\Repositories\CartRuleCouponUsageRepository; class CartRule { @@ -153,7 +153,9 @@ class CartRule if (Cart::getCurrentCustomer()->check()) { $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; } else { - if ($customerGuestGroup = $this->customerGroupRepository->findOneByField('code', 'guest')) { + $customerGuestGroup = $this->customerGroupRepository->getCustomerGuestGroup(); + + if ($customerGuestGroup) { $customerGroupId = $customerGuestGroup->id; } } diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php index 2d7413526..8420805e9 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php @@ -3,8 +3,8 @@ namespace Webkul\CatalogRule\Helpers; use Carbon\Carbon; -use Webkul\CatalogRule\Repositories\CatalogRuleProductPriceRepository; use Webkul\Customer\Repositories\CustomerGroupRepository; +use Webkul\CatalogRule\Repositories\CatalogRuleProductPriceRepository; class CatalogRuleProductPrice { @@ -161,7 +161,7 @@ class CatalogRuleProductPrice case 'by_fixed': $price = max(0, $price - $rule->discount_amount); - + break; case 'by_percent': @@ -191,7 +191,7 @@ class CatalogRuleProductPrice } /** - * Get catalog rules product price for specific date, channel and customer group + * Get catalog rules product price for specific date, channel and customer group. * * @param \Webkul\Product\Contracts\Product $product * @return array|void @@ -201,7 +201,7 @@ class CatalogRuleProductPrice if ($this->getCurrentCustomer()->check()) { $customerGroupId = $this->getCurrentCustomer()->user()->customer_group_id; } else { - $customerGroup = $this->customerGroupRepository->findOneByField('code', 'guest'); + $customerGroup = $this->customerGroupRepository->getCustomerGuestGroup(); if (! $customerGroup) { return; @@ -210,11 +210,6 @@ class CatalogRuleProductPrice $customerGroupId = $customerGroup->id; } - return $this->catalogRuleProductPriceRepository->findOneWhere([ - 'product_id' => $product->id, - 'channel_id' => core()->getCurrentChannel()->id, - 'customer_group_id' => $customerGroupId, - 'rule_date' => Carbon::now()->format('Y-m-d'), - ]); + return $this->catalogRuleProductPriceRepository->checkInLoadedCatalogRulePrice($product, $customerGroupId); } } \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductPriceRepository.php b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductPriceRepository.php index 711a2026e..87f4b2964 100644 --- a/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductPriceRepository.php +++ b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductPriceRepository.php @@ -2,12 +2,13 @@ namespace Webkul\CatalogRule\Repositories; +use Illuminate\Support\Carbon; use Webkul\Core\Eloquent\Repository; class CatalogRuleProductPriceRepository extends Repository { /** - * Specify Model class name + * Specify Model class name. * * @return mixed */ @@ -15,4 +16,25 @@ class CatalogRuleProductPriceRepository extends Repository { return 'Webkul\CatalogRule\Contracts\CatalogRuleProductPrice'; } + + /** + * Check if catalog rule prices already loaded. If already loaded then load from it. + * + * @return object + */ + public function checkInLoadedCatalogRulePrice($product, $customerGroupId) + { + static $catalogRulePrices = []; + + if (array_key_exists($product->id, $catalogRulePrices)) { + return $catalogRulePrices[$product->id]; + } + + return $catalogRulePrices[$product->id] = $this->findOneWhere([ + 'product_id' => $product->id, + 'channel_id' => core()->getCurrentChannel()->id, + 'customer_group_id' => $customerGroupId, + 'rule_date' => Carbon::now()->format('Y-m-d'), + ]); + } } \ No newline at end of file diff --git a/packages/Webkul/Core/src/Core.php b/packages/Webkul/Core/src/Core.php index cc3046ca8..0e6b04c8a 100755 --- a/packages/Webkul/Core/src/Core.php +++ b/packages/Webkul/Core/src/Core.php @@ -4,14 +4,14 @@ namespace Webkul\Core; use Carbon\Carbon; use Webkul\Core\Models\Channel; -use Webkul\Core\Repositories\CurrencyRepository; -use Webkul\Core\Repositories\ExchangeRateRepository; -use Webkul\Core\Repositories\CountryRepository; -use Webkul\Core\Repositories\CountryStateRepository; -use Webkul\Core\Repositories\ChannelRepository; -use Webkul\Core\Repositories\LocaleRepository; -use Webkul\Core\Repositories\CoreConfigRepository; use Illuminate\Support\Facades\Config; +use Webkul\Core\Repositories\LocaleRepository; +use Webkul\Core\Repositories\ChannelRepository; +use Webkul\Core\Repositories\CountryRepository; +use Webkul\Core\Repositories\CurrencyRepository; +use Webkul\Core\Repositories\CoreConfigRepository; +use Webkul\Core\Repositories\CountryStateRepository; +use Webkul\Core\Repositories\ExchangeRateRepository; use Webkul\Customer\Repositories\CustomerGroupRepository; class Core @@ -72,9 +72,20 @@ class Core */ protected $coreConfigRepository; - /** @var Channel */ + /** + * @var \Webkul\Core\Models\Channel + */ private static $channel; + /** + * Register your core config keys here which you don't want to + * load in static array. These keys will load from database + * everytime the `getConfigData` method is called. + */ + private $coreConfigExceptions = [ + 'catalog.products.guest-checkout.allow-guest-checkout' + ]; + /** * Create a new instance. * @@ -118,7 +129,7 @@ class Core } /** - * Returns all channels + * Returns all channels. * * @return \Illuminate\Support\Collection */ @@ -134,7 +145,7 @@ class Core } /** - * Returns currenct channel models + * Returns currenct channel models. * * @return \Webkul\Core\Contracts\Channel */ @@ -158,7 +169,7 @@ class Core } /** - * Set the current channel + * Set the current channel. * * @param Channel $channel */ @@ -168,7 +179,7 @@ class Core } /** - * Returns currenct channel code + * Returns currenct channel code. * * @return \Webkul\Core\Contracts\Channel */ @@ -184,7 +195,7 @@ class Core } /** - * Returns default channel models + * Returns default channel models. * * @return \Webkul\Core\Contracts\Channel */ @@ -206,7 +217,7 @@ class Core } /** - * Returns the default channel code configured in config/app.php + * Returns the default channel code configured in `config/app.php`. * * @return string */ @@ -222,7 +233,7 @@ class Core } /** - * Returns all locales + * Returns all locales. * * @return \Illuminate\Support\Collection */ @@ -238,7 +249,7 @@ class Core } /** - * Returns current locale + * Returns current locale. * * @return \Webkul\Core\Contracts\Locale */ @@ -260,7 +271,7 @@ class Core } /** - * Returns all Customer Groups + * Returns all customer groups. * * @return \Illuminate\Support\Collection */ @@ -276,7 +287,7 @@ class Core } /** - * Returns all currencies + * Returns all currencies. * * @return \Illuminate\Support\Collection */ @@ -292,7 +303,7 @@ class Core } /** - * Returns base channel's currency model + * Returns base channel's currency model. * * @return \Webkul\Core\Contracts\Currency */ @@ -314,7 +325,7 @@ class Core } /** - * Returns base channel's currency code + * Returns base channel's currency code. * * @return string */ @@ -330,7 +341,7 @@ class Core } /** - * Returns base channel's currency model + * Returns base channel's currency model. * * @return \Webkul\Core\Contracts\Currency */ @@ -348,7 +359,7 @@ class Core } /** - * Returns base channel's currency code + * Returns base channel's currency code. * * @return string */ @@ -364,7 +375,7 @@ class Core } /** - * Returns current channel's currency model + * Returns current channel's currency model. * * @return \Webkul\Core\Contracts\Currency */ @@ -386,7 +397,7 @@ class Core } /** - * Returns current channel's currency code + * Returns current channel's currency code. * * @return string */ @@ -402,7 +413,27 @@ class Core } /** - * Converts price + * Returns exchange rates. + * + * @return object + */ + public function getExchangeRate($targetCurrencyId) + { + static $exchangeRate; + + if ($exchangeRate || $exchangeRate === '') { + return $exchangeRate; + } + + $found = $this->exchangeRateRepository->findOneWhere([ + 'target_currency' => $targetCurrencyId, + ]); + + return $exchangeRate = ($found ? $found : ''); + } + + /** + * Converts price. * * @param float $amount * @param string $targetCurrencyCode @@ -438,11 +469,9 @@ class Core return $amount; } - $exchangeRate = $this->exchangeRateRepository->findOneWhere([ - 'target_currency' => $targetCurrency->id, - ]); + $exchangeRate = $this->getExchangeRate($targetCurrency->id); - if (null === $exchangeRate || ! $exchangeRate->rate) { + if ('' === $exchangeRate || null === $exchangeRate || ! $exchangeRate->rate) { return $amount; } @@ -456,7 +485,7 @@ class Core } /** - * Converts to base price + * Converts to base price. * * @param float $amount * @param string $targetCurrencyCode @@ -485,7 +514,7 @@ class Core } /** - * Format and convert price with currency symbol + * Format and convert price with currency symbol. * * @param float $price * @@ -501,7 +530,7 @@ class Core } /** - * Return currency symbol from currency code + * Return currency symbol from currency code. * * @param float $price * @@ -515,7 +544,7 @@ class Core } /** - * Format and convert price with currency symbol + * Format and convert price with currency symbol. * * @param float $price * @@ -532,7 +561,7 @@ class Core } /** - * Format and convert price with currency symbol + * Format and convert price with currency symbol. * * @return array */ @@ -547,14 +576,14 @@ class Core $pattern = str_replace("#,##0.00", "%v", $pattern); return [ - 'symbol' => core()->currencySymbol(core()->getCurrentCurrencyCode()), + 'symbol' => $this->currencySymbol($this->getCurrentCurrencyCode()), 'decimal' => $formater->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), 'format' => $pattern, ]; } /** - * Format price with base currency symbol + * Format price with base currency symbol. * * @param float $price * @@ -582,7 +611,7 @@ class Core } /** - * Checks if current date of the given channel (in the channel timezone) is within the range + * Checks if current date of the given channel (in the channel timezone) is within the range. * * @param int|string|\Webkul\Core\Contracts\Channel $channel * @param string|null $dateFrom @@ -616,7 +645,7 @@ class Core } /** - * Get channel timestamp, timstamp will be builded with channel timezone settings + * Get channel timestamp, timstamp will be builded with channel timezone settings. * * @param \Webkul\Core\Contracts\Channel $channel * @@ -638,7 +667,7 @@ class Core } /** - * Check whether sql date is empty + * Check whether sql date is empty. * * @param string $date * @@ -671,7 +700,7 @@ class Core } /** - * Retrieve information from payment configuration + * Retrieve information from payment configuration. * * @param string $field * @param int|string|null $channelId @@ -681,51 +710,20 @@ class Core */ public function getConfigData($field, $channel = null, $locale = null) { - if (null === $channel) { - $channel = request()->get('channel') ?: ($this->getCurrentChannelCode() ?: $this->getDefaultChannelCode()); - } + static $loadedConfigs = []; - if (null === $locale) { - $locale = request()->get('locale') ?: app()->getLocale(); - } - - $fields = $this->getConfigField($field); - - $channel_based = false; - $locale_based = false; - - if (isset($fields['channel_based']) && $fields['channel_based']) { - $channel_based = true; - } - - if (isset($fields['locale_based']) && $fields['locale_based']) { - $locale_based = true; - } - - if (isset($fields['channel_based']) && $fields['channel_based']) { - if (isset($fields['locale_based']) && $fields['locale_based']) { - $coreConfigValue = $this->coreConfigRepository->findOneWhere([ - 'code' => $field, - 'channel_code' => $channel, - 'locale_code' => $locale, - ]); - } else { - $coreConfigValue = $this->coreConfigRepository->findOneWhere([ - 'code' => $field, - 'channel_code' => $channel, - ]); - } + if (array_key_exists($field, $loadedConfigs) && ! in_array($field, $this->coreConfigExceptions)) { + $coreConfigValue = $loadedConfigs[$field]; } else { - if (isset($fields['locale_based']) && $fields['locale_based']) { - $coreConfigValue = $this->coreConfigRepository->findOneWhere([ - 'code' => $field, - 'locale_code' => $locale, - ]); - } else { - $coreConfigValue = $this->coreConfigRepository->findOneWhere([ - 'code' => $field, - ]); + if (null === $channel) { + $channel = request()->get('channel') ?: ($this->getCurrentChannelCode() ?: $this->getDefaultChannelCode()); } + + if (null === $locale) { + $locale = request()->get('locale') ?: app()->getLocale(); + } + + $loadedConfigs[$field] = $coreConfigValue = $this->getCoreConfigValue($field, $channel, $locale); } if (! $coreConfigValue) { @@ -742,7 +740,7 @@ class Core } /** - * Retrieve a group of information from the core config table + * Retrieve a group of information from the core config table. * * @param mixed $criteria * @@ -754,7 +752,7 @@ class Core } /** - * Retrieve all countries + * Retrieve all countries. * * @return \Illuminate\Support\Collection */ @@ -764,7 +762,7 @@ class Core } /** - * Returns country name by code + * Returns country name by code. * * @param string $code * @@ -778,7 +776,7 @@ class Core } /** - * Retrieve all country states + * Retrieve all country states. * * @param string $countryCode * @@ -790,7 +788,7 @@ class Core } /** - * Retrieve all grouped states by country code + * Retrieve all grouped states by country code. * * @return \Illuminate\Support\Collection */ @@ -806,7 +804,7 @@ class Core } /** - * Retrieve all grouped states by country code + * Retrieve all grouped states by country code. * * @return \Illuminate\Support\Collection */ @@ -824,7 +822,7 @@ class Core } /** - * Returns time intervals + * Returns time intervals. * * @param \Illuminate\Support\Carbon $startDate * @param \Illuminate\Support\Carbon $endDate @@ -884,7 +882,6 @@ class Core } /** - * * @param string $date * @param int $day * @@ -906,7 +903,7 @@ class Core } /** - * Method to sort through the acl items and put them in order + * Method to sort through the acl items and put them in order. * * @param array $items * @@ -1022,6 +1019,86 @@ class Core return $array; } + /** + * @param array $array1 + * + * @return array + */ + public function convertEmptyStringsToNull($array) + { + foreach ($array as $key => $value) { + if ($value == "" || $value == "null") { + $array[$key] = null; + } + } + + return $array; + } + + /** + * Create singleton object through single facade. + * + * @param string $className + * + * @return object + */ + public function getSingletonInstance($className) + { + static $instance = []; + + if (array_key_exists($className, $instance)) { + return $instance[$className]; + } + + return $instance[$className] = app($className); + } + + /** + * Returns a string as selector part for identifying elements in views. + * + * @param float $taxRate + * + * @return string + */ + public static function taxRateAsIdentifier(float $taxRate): string + { + return str_replace('.', '_', (string)$taxRate); + } + + /** + * Get Shop email sender details. + * + * @return array + */ + public function getSenderEmailDetails() + { + $sender_name = $this->getConfigData('general.general.email_settings.sender_name') ? $this->getConfigData('general.general.email_settings.sender_name') : config('mail.from.name'); + + $sender_email = $this->getConfigData('general.general.email_settings.shop_email_from') ? $this->getConfigData('general.general.email_settings.shop_email_from') : config('mail.from.address'); + + return [ + 'name' => $sender_name, + 'email' => $sender_email, + ]; + } + + /** + * Get Admin email details. + * + * @return array + */ + public function getAdminEmailDetails() + { + $admin_name = $this->getConfigData('general.general.email_settings.admin_name') ? $this->getConfigData('general.general.email_settings.admin_name') : config('mail.admin.name'); + + $admin_email = $this->getConfigData('general.general.email_settings.admin_email') ? $this->getConfigData('general.general.email_settings.admin_email') : config('mail.admin.address'); + + return [ + 'name' => $admin_name, + 'email' => $admin_email, + ]; + } + /** * @param array $array1 * @param array $array2 @@ -1044,82 +1121,38 @@ class Core } /** - * @param array $array1 - * - * @return array + * Get core config values. */ - public function convertEmptyStringsToNull($array) + protected function getCoreConfigValue($field, $channel, $locale) { - foreach ($array as $key => $value) { - if ($value == "" || $value == "null") { - $array[$key] = null; + $fields = $this->getConfigField($field); + + if (isset($fields['channel_based']) && $fields['channel_based']) { + if (isset($fields['locale_based']) && $fields['locale_based']) { + $coreConfigValue = $this->coreConfigRepository->findOneWhere([ + 'code' => $field, + 'channel_code' => $channel, + 'locale_code' => $locale, + ]); + } else { + $coreConfigValue = $this->coreConfigRepository->findOneWhere([ + 'code' => $field, + 'channel_code' => $channel, + ]); + } + } else { + if (isset($fields['locale_based']) && $fields['locale_based']) { + $coreConfigValue = $this->coreConfigRepository->findOneWhere([ + 'code' => $field, + 'locale_code' => $locale, + ]); + } else { + $coreConfigValue = $this->coreConfigRepository->findOneWhere([ + 'code' => $field, + ]); } } - return $array; - } - - /** - * Create singletom object through single facade - * - * @param string $className - * - * @return object - */ - public function getSingletonInstance($className) - { - static $instance = []; - - if (array_key_exists($className, $instance)) { - return $instance[$className]; - } - - return $instance[$className] = app($className); - } - - /** - * Returns a string as selector part for identifying elements in views - * - * @param float $taxRate - * - * @return string - */ - public static function taxRateAsIdentifier(float $taxRate): string - { - return str_replace('.', '_', (string)$taxRate); - } - - /** - * Get Shop email sender details - * - * @return array - */ - public function getSenderEmailDetails() - { - $sender_name = core()->getConfigData('general.general.email_settings.sender_name') ? core()->getConfigData('general.general.email_settings.sender_name') : config('mail.from.name'); - - $sender_email = core()->getConfigData('general.general.email_settings.shop_email_from') ? core()->getConfigData('general.general.email_settings.shop_email_from') : config('mail.from.address'); - - return [ - 'name' => $sender_name, - 'email' => $sender_email, - ]; - } - - /** - * Get Admin email details - * - * @return array - */ - public function getAdminEmailDetails() - { - $admin_name = core()->getConfigData('general.general.email_settings.admin_name') ? core()->getConfigData('general.general.email_settings.admin_name') : config('mail.admin.name'); - - $admin_email = core()->getConfigData('general.general.email_settings.admin_email') ? core()->getConfigData('general.general.email_settings.admin_email') : config('mail.admin.address'); - - return [ - 'name' => $admin_name, - 'email' => $admin_email, - ]; + return $coreConfigValue; } } \ No newline at end of file diff --git a/packages/Webkul/Core/src/Models/Channel.php b/packages/Webkul/Core/src/Models/Channel.php index 45741f123..940c2f3a8 100755 --- a/packages/Webkul/Core/src/Models/Channel.php +++ b/packages/Webkul/Core/src/Models/Channel.php @@ -7,6 +7,7 @@ use Webkul\Category\Models\CategoryProxy; use Webkul\Core\Eloquent\TranslatableModel; use Webkul\Inventory\Models\InventorySourceProxy; use Webkul\Core\Contracts\Channel as ChannelContract; +use Webkul\Product\Models\ProductOrderedInventoryProxy; class Channel extends TranslatableModel implements ChannelContract { diff --git a/packages/Webkul/Customer/src/Helpers/Wishlist.php b/packages/Webkul/Customer/src/Helpers/Wishlist.php index 039b54c40..64cdb88ba 100644 --- a/packages/Webkul/Customer/src/Helpers/Wishlist.php +++ b/packages/Webkul/Customer/src/Helpers/Wishlist.php @@ -2,28 +2,8 @@ namespace Webkul\Customer\Helpers; -use Webkul\Customer\Repositories\WishlistRepository; - class Wishlist { - /** - * WishlistRepository object - * - * @var \Webkul\Customer\Repositories\WishlistRepository - */ - protected $wishlistRepository; - - /** - * Create a new controller instance. - * - * @param \Webkul\Customer\Repositories\WishlistRepository - * @return void - */ - public function __construct(WishlistRepository $wishlistRepository) - { - $this->wishlistRepository = $wishlistRepository; - } - /** * Returns wishlist products for current customer. * @@ -34,12 +14,10 @@ class Wishlist { $wishlist = false; - if (auth()->guard('customer')->user()) { - $wishlist = $this->wishlistRepository->findOneWhere([ - 'channel_id' => core()->getCurrentChannel()->id, - 'product_id' => $product->product_id, - 'customer_id' => auth()->guard('customer')->user()->id, - ]); + if ($customer = auth()->guard('customer')->user()) { + $wishlist = $customer->wishlist_items->filter(function ($item) use ($product) { + return $item->channel_id == core()->getCurrentChannel()->id && $item->product_id == $product->product_id; + })->first(); } if ($wishlist) { diff --git a/packages/Webkul/Customer/src/Repositories/CustomerGroupRepository.php b/packages/Webkul/Customer/src/Repositories/CustomerGroupRepository.php index 8cd2c01b6..db1fdc175 100755 --- a/packages/Webkul/Customer/src/Repositories/CustomerGroupRepository.php +++ b/packages/Webkul/Customer/src/Repositories/CustomerGroupRepository.php @@ -42,4 +42,20 @@ class CustomerGroupRepository extends Repository return $customer; } + + /** + * Returns guest group. + * + * @return object + */ + public function getCustomerGuestGroup() + { + static $customerGuestGroup; + + if ($customerGuestGroup) { + return $customerGuestGroup; + } + + return $customerGuestGroup = $this->findOneByField('code', 'guest'); + } } \ No newline at end of file diff --git a/packages/Webkul/Inventory/src/Repositories/InventorySourceRepository.php b/packages/Webkul/Inventory/src/Repositories/InventorySourceRepository.php index 3cf0e5c63..4dfd98ac6 100755 --- a/packages/Webkul/Inventory/src/Repositories/InventorySourceRepository.php +++ b/packages/Webkul/Inventory/src/Repositories/InventorySourceRepository.php @@ -15,4 +15,24 @@ class InventorySourceRepository extends Repository { return 'Webkul\Inventory\Contracts\InventorySource'; } + + /** + * Returns channel inventory source ids. + * + * @return collection + */ + public function getChannelInventorySourceIds() + { + static $channelInventorySourceIds; + + if ($channelInventorySourceIds) { + return $channelInventorySourceIds; + } + + $found = core()->getCurrentChannel()->inventory_sources() + ->where('status', 1) + ->pluck('id'); + + return $channelInventorySourceIds = ($found ? $found : collect([])); + } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Helpers/ProductImage.php b/packages/Webkul/Product/src/Helpers/ProductImage.php index 8eb50bb3b..8bf33630c 100755 --- a/packages/Webkul/Product/src/Helpers/ProductImage.php +++ b/packages/Webkul/Product/src/Helpers/ProductImage.php @@ -35,10 +35,16 @@ class ProductImage extends AbstractProduct */ public function getGalleryImages($product) { + static $loadedGalleryImages = []; + if (! $product) { return []; } + if (array_key_exists($product->id, $loadedGalleryImages)) { + return $loadedGalleryImages[$product->id]; + } + $images = []; foreach ($product->images as $image) { @@ -63,16 +69,58 @@ class ProductImage extends AbstractProduct ]; } - return $images; + return $loadedGalleryImages[$product->id] = $images; } /** - * Get product's base image + * This method will first check whether the gallery images are already + * present or not. If not then it will load from the product. + * + * @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product + * @param array + * @return array + */ + public function getProductBaseImage($product, array $galleryImages = null) + { + static $loadedBaseImages = []; + + if (array_key_exists($product->id, $loadedBaseImages)) { + return $loadedBaseImages[$product->id]; + } + + return $loadedBaseImages[$product->id] = $galleryImages + ? $galleryImages[0] + : $this->otherwiseLoadFromProduct($product); + } + + /** + * Get product varient image if available otherwise product base image. + * + * @param \Webkul\Customer\Contracts\Wishlist $item + * @return array + */ + public function getProductImage($item) + { + if ($item instanceof \Webkul\Customer\Contracts\Wishlist) { + if (isset($item->additional['selected_configurable_option'])) { + $product = $this->productRepository->find($item->additional['selected_configurable_option']); + } else { + $product = $item->product; + } + } else { + $product = $item->product; + } + + return $this->getProductBaseImage($product); + } + + /** + * Load product's base image. * * @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product * @return array */ - public function getProductBaseImage($product) + protected function otherwiseLoadFromProduct($product) { $images = $product ? $product->images : null; @@ -94,25 +142,4 @@ class ProductImage extends AbstractProduct return $image; } - - /** - * Get product varient image if available otherwise product base image - * - * @param \Webkul\Customer\Contracts\Wishlist $item - * @return array - */ - public function getProductImage($item) - { - if ($item instanceof \Webkul\Customer\Contracts\Wishlist) { - if (isset($item->additional['selected_configurable_option'])) { - $product = $this->productRepository->find($item->additional['selected_configurable_option']); - } else { - $product = $item->product; - } - } else { - $product = $item->product; - } - - return $this->getProductBaseImage($product); - } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Helpers/Review.php b/packages/Webkul/Product/src/Helpers/Review.php index 993e90b14..6582888b6 100755 --- a/packages/Webkul/Product/src/Helpers/Review.php +++ b/packages/Webkul/Product/src/Helpers/Review.php @@ -74,6 +74,28 @@ class Review extends AbstractProduct return $totalRating[$product->id] = $product->reviews()->where('status', 'approved')->sum('rating'); } + /** + * Returns reviews with ratings. + * + * @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product + * + * @return collection + */ + public function getReviewsWithRatings($product) + { + static $reviews = []; + + if (array_key_exists($product->id, $reviews)) { + return $reviews[$product->id]; + } + + return $reviews[$product->id] = $product->reviews()->where('status', 'approved') + ->select('rating', DB::raw('count(*) as total')) + ->groupBy('rating') + ->orderBy('rating', 'desc') + ->get(); + } + /** * Returns the Percentage rating of the product * @@ -82,11 +104,7 @@ class Review extends AbstractProduct */ public function getPercentageRating($product) { - $reviews = $product->reviews()->where('status', 'approved') - ->select('rating', DB::raw('count(*) as total')) - ->groupBy('rating') - ->orderBy('rating', 'desc') - ->get(); + $reviews = $this->getReviewsWithRatings($product); $totalReviews = $this->getTotalReviews($product); diff --git a/packages/Webkul/Product/src/Models/Product.php b/packages/Webkul/Product/src/Models/Product.php index 269ebb6b2..84f6bf6a5 100755 --- a/packages/Webkul/Product/src/Models/Product.php +++ b/packages/Webkul/Product/src/Models/Product.php @@ -12,6 +12,7 @@ use Webkul\Attribute\Models\AttributeFamilyProxy; use Webkul\Inventory\Models\InventorySourceProxy; use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Product\Contracts\Product as ProductContract; +use Webkul\CatalogRule\Models\CatalogRuleProductPriceProxy; class Product extends Model implements ProductContract { @@ -338,6 +339,23 @@ class Product extends Model implements ProductContract return parent::getAttribute($key); } + /** + * Check in loaded family attributes. + * + * @return object + */ + public function checkInLoadedFamilyAttributes() + { + static $loadedFamilyAttributes = []; + + if (array_key_exists($this->attribute_family_id, $loadedFamilyAttributes)) { + return $loadedFamilyAttributes[$this->attribute_family_id]; + } + + return $loadedFamilyAttributes[$this->attribute_family_id] = core()->getSingletonInstance(AttributeRepository::class) + ->getFamilyAttributes($this->attribute_family); + } + /** * @return array */ @@ -348,9 +366,7 @@ class Product extends Model implements ProductContract $hiddenAttributes = $this->getHidden(); if (isset($this->id)) { - $familyAttributes = core() - ->getSingletonInstance(AttributeRepository::class) - ->getFamilyAttributes($this->attribute_family); + $familyAttributes = $this->checkInLoadedFamilyAttributes(); foreach ($familyAttributes as $attribute) { if (in_array($attribute->code, $hiddenAttributes)) { diff --git a/packages/Webkul/Product/src/Models/ProductFlat.php b/packages/Webkul/Product/src/Models/ProductFlat.php index 92a199407..c9bba615f 100644 --- a/packages/Webkul/Product/src/Models/ProductFlat.php +++ b/packages/Webkul/Product/src/Models/ProductFlat.php @@ -121,16 +121,14 @@ class ProductFlat extends Model implements ProductFlatContract */ public function images() { - return (ProductImageProxy::modelClass()) - ::where('product_images.product_id', $this->product_id) - ->select('product_images.*'); + return $this->hasMany(ProductImageProxy::modelClass(), 'product_id', 'product_id'); } /** * The videos that belong to the product. */ public function videos() - { + { return $this->product->videos(); } diff --git a/packages/Webkul/Product/src/Repositories/ProductCustomerGroupPriceRepository.php b/packages/Webkul/Product/src/Repositories/ProductCustomerGroupPriceRepository.php index 5a42c9421..ea773ee19 100755 --- a/packages/Webkul/Product/src/Repositories/ProductCustomerGroupPriceRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductCustomerGroupPriceRepository.php @@ -2,15 +2,13 @@ namespace Webkul\Product\Repositories; -use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use Illuminate\Http\UploadedFile; use Webkul\Core\Eloquent\Repository; class ProductCustomerGroupPriceRepository extends Repository { /** - * Specify Model class name + * Specify Model class name. * * @return mixed */ @@ -50,4 +48,22 @@ class ProductCustomerGroupPriceRepository extends Repository $this->delete($customerGroupPriceId); } } + + /** + * Check if product customer group prices already loaded then load from it. + * + * @return object + */ + public function checkInLoadedCustomerGroupPrice($product, $customerGroupId) + { + static $customerGroupPrices = []; + + if (array_key_exists($product->id, $customerGroupPrices)) { + return $customerGroupPrices[$product->id]; + } + + return $customerGroupPrices[$product->id] = $product->customer_group_prices->filter(function ($customerGroupPrice) use ($customerGroupId) { + return $customerGroupPrice->customer_group_id == $customerGroupId || is_null($customerGroupPrice->customer_group_id); + }); + } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Repositories/ProductFlatRepository.php b/packages/Webkul/Product/src/Repositories/ProductFlatRepository.php index db994b0a8..40a34df47 100644 --- a/packages/Webkul/Product/src/Repositories/ProductFlatRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductFlatRepository.php @@ -19,11 +19,17 @@ class ProductFlatRepository extends Repository */ public function getCategoryProductMaximumPrice($category = null) { + static $loadedCategoryMaxPrice = []; + if (! $category) { return $this->model->max('max_price'); } - return $this->model + if (array_key_exists($category->id, $loadedCategoryMaxPrice)) { + return $loadedCategoryMaxPrice[$category->id]; + } + + return $loadedCategoryMaxPrice[$category->id] = $this->model ->leftJoin('product_categories', 'product_flat.product_id', 'product_categories.product_id') ->where('product_categories.category_id', $category->id) ->max('max_price'); @@ -84,6 +90,12 @@ class ProductFlatRepository extends Repository */ public function getProductsRelatedFilterableAttributes($category) { + static $loadedCategoryAttributes = []; + + if (array_key_exists($category->id, $loadedCategoryAttributes)) { + return $loadedCategoryAttributes[$category->id]; + } + $categoryFilterableAttributes = $category->filterableAttributes->pluck('id')->toArray(); $productCategoryArrributes = $this->getCategoryProductAttribute($category->id); @@ -95,7 +107,7 @@ class ProductFlatRepository extends Repository } ])->whereIn('id', $allFilterableAttributes)->get(); - return $attributes; + return $loadedCategoryAttributes[$category->id] = $attributes; } /** diff --git a/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php b/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php index d80731963..12422d80c 100755 --- a/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php @@ -2,13 +2,12 @@ namespace Webkul\Product\Repositories; -use Illuminate\Container\Container as App; use Webkul\Core\Eloquent\Repository; class ProductInventoryRepository extends Repository { /** - * Specify Model class name + * Specify Model class name. * * @return mixed */ @@ -49,4 +48,20 @@ class ProductInventoryRepository extends Repository } } } + + /** + * Check if product inventories are already loaded. If already loaded then load from it. + * + * @return object + */ + public function checkInLoadedProductInventories($product) + { + static $productInventories = []; + + if (array_key_exists($product->id, $productInventories)) { + return $productInventories[$product->id]; + } + + return $productInventories[$product->id] = $product->inventories; + } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index 5ac820274..1a2555558 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -12,8 +12,11 @@ use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Product\Datatypes\CartItemValidationResult; use Webkul\Product\Repositories\ProductImageRepository; use Webkul\Product\Repositories\ProductVideoRepository; +use Webkul\Customer\Repositories\CustomerGroupRepository; +use Webkul\Inventory\Repositories\InventorySourceRepository; use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductAttributeValueRepository; +use Webkul\Product\Repositories\ProductCustomerGroupPriceRepository; abstract class AbstractType { @@ -285,7 +288,7 @@ abstract class AbstractType $this->productVideoRepository->uploadVideos($data, $product); - app('Webkul\Product\Repositories\ProductCustomerGroupPriceRepository')->saveCustomerGroupPrices($data, + app(ProductCustomerGroupPriceRepository::class)->saveCustomerGroupPrices($data, $product); } @@ -432,20 +435,18 @@ abstract class AbstractType { $total = 0; - $channelInventorySourceIds = core()->getCurrentChannel() - ->inventory_sources() - ->where('status', 1) - ->pluck('id'); + $channelInventorySourceIds = app(InventorySourceRepository::class)->getChannelInventorySourceIds(); - foreach ($this->product->inventories as $inventory) { - if (is_numeric($index = $channelInventorySourceIds->search($inventory->inventory_source_id))) { + $productInventories = $this->productInventoryRepository->checkInLoadedProductInventories($this->product); + + foreach ($productInventories as $inventory) { + if (is_numeric($channelInventorySourceIds->search($inventory->inventory_source_id))) { $total += $inventory->qty; } } $orderedInventory = $this->product->ordered_inventories() - ->where('channel_id', core()->getCurrentChannel()->id) - ->first(); + ->where('channel_id', core()->getCurrentChannel()->id)->first(); if ($orderedInventory) { $total -= $orderedInventory->qty; @@ -570,7 +571,9 @@ abstract class AbstractType $rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product); - if ((is_null($this->product->special_price) || ! (float)$this->product->special_price) + $specialPrice = $this->product->special_price; + + if ((is_null($specialPrice) || ! (float) $specialPrice) && ! $rulePrice && $customerGroupPrice == $this->product->price ) { @@ -579,7 +582,7 @@ abstract class AbstractType $haveSpecialPrice = false; - if (! (float)$this->product->special_price) { + if (! (float) $specialPrice) { if ($rulePrice && $rulePrice->price < $this->product->price) { $this->product->special_price = $rulePrice->price; @@ -630,18 +633,14 @@ abstract class AbstractType if (Cart::getCurrentCustomer()->check()) { $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; } else { - $customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository'); + $customerGuestGroup = app(CustomerGroupRepository::class)->getCustomerGuestGroup(); - if ($customerGuestGroup = $customerGroupRepository->findOneByField('code', 'guest')) { + if ($customerGuestGroup) { $customerGroupId = $customerGuestGroup->id; } } - $customerGroupPrices = $product->customer_group_prices()->where(function ($query) use ($customerGroupId) { - $query->where('customer_group_id', $customerGroupId) - ->orWhereNull('customer_group_id'); - } - )->get(); + $customerGroupPrices = app(ProductCustomerGroupPriceRepository::class)->checkInLoadedCustomerGroupPrice($product, $customerGroupId); if (!$customerGroupPrices->count()) { return $product->price; @@ -924,4 +923,19 @@ abstract class AbstractType return false; } + /** + * Check in loaded saleable. + * + * @return object + */ + public function checkInLoadedSaleableChecks($product, $callback) + { + static $loadedSaleableChecks = []; + + if (array_key_exists($product->id, $loadedSaleableChecks)) { + return $loadedSaleableChecks[$product->id]; + } + + return $loadedSaleableChecks[$product->id] = $callback($product); + } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Type/Configurable.php b/packages/Webkul/Product/src/Type/Configurable.php index 9236a85cf..f41eacf7d 100644 --- a/packages/Webkul/Product/src/Type/Configurable.php +++ b/packages/Webkul/Product/src/Type/Configurable.php @@ -539,7 +539,7 @@ class Configurable extends AbstractType $product = $item->child->product; } else { $product = $item->product; - } + } } } diff --git a/packages/Webkul/Product/src/Type/Grouped.php b/packages/Webkul/Product/src/Type/Grouped.php index 1f7f1c42d..1e8980b21 100644 --- a/packages/Webkul/Product/src/Type/Grouped.php +++ b/packages/Webkul/Product/src/Type/Grouped.php @@ -111,7 +111,7 @@ class Grouped extends AbstractType */ public function getChildrenIds() { - return array_unique($this->product->grouped_products()->pluck('associated_product_id')->toArray()); + return array_unique($this->product->grouped_products->pluck('associated_product_id')->toArray()); } /** diff --git a/packages/Webkul/Product/src/Type/Simple.php b/packages/Webkul/Product/src/Type/Simple.php index 40934f562..d6fcb487a 100644 --- a/packages/Webkul/Product/src/Type/Simple.php +++ b/packages/Webkul/Product/src/Type/Simple.php @@ -5,14 +5,14 @@ namespace Webkul\Product\Type; class Simple extends AbstractType { /** - * Skip attribute for simple product type + * Skip attribute for simple product type. * * @var array */ protected $skipAttributes = []; /** - * These blade files will be included in product edit page + * These blade files will be included in product edit page. * * @var array */ @@ -26,33 +26,36 @@ class Simple extends AbstractType ]; /** - * Show quantity box + * Show quantity box. * * @var bool */ protected $showQuantityBox = true; /** - * Return true if this product type is saleable + * Return true if this product type is saleable. Saleable check added because + * this is the point where all parent product will recall this. * * @return bool */ public function isSaleable() { - if (! $this->product->status) { + return $this->checkInLoadedSaleableChecks($this->product, function ($product) { + if (! $product->status) { + return false; + } + + if (is_callable(config('products.isSaleable')) && + call_user_func(config('products.isSaleable'), $product) === false) { + return false; + } + + if ($this->haveSufficientQuantity(1)) { + return true; + } + return false; - } - - if (is_callable(config('products.isSaleable')) && - call_user_func(config('products.isSaleable'), $this->product) === false) { - return false; - } - - if ($this->haveSufficientQuantity(1)) { - return true; - } - - return false; + }); } /** diff --git a/packages/Webkul/Shop/src/Http/Middleware/Currency.php b/packages/Webkul/Shop/src/Http/Middleware/Currency.php index 52a3d9265..5655724ae 100755 --- a/packages/Webkul/Shop/src/Http/Middleware/Currency.php +++ b/packages/Webkul/Shop/src/Http/Middleware/Currency.php @@ -2,8 +2,8 @@ namespace Webkul\Shop\Http\Middleware; -use Webkul\Core\Repositories\CurrencyRepository; use Closure; +use Webkul\Core\Repositories\CurrencyRepository; class Currency { diff --git a/packages/Webkul/Shop/src/Resources/views/guest/compare/compare-products.blade.php b/packages/Webkul/Shop/src/Resources/views/guest/compare/compare-products.blade.php index b6f65a053..85fe7368a 100644 --- a/packages/Webkul/Shop/src/Resources/views/guest/compare/compare-products.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/guest/compare/compare-products.blade.php @@ -68,7 +68,7 @@ @case('addToCartHtml')