From f3f61e3c91c40e98ce4c61de702e88a237f615f8 Mon Sep 17 00:00:00 2001 From: jitendra Date: Wed, 10 Apr 2019 12:10:46 +0530 Subject: [PATCH] Optimized performance --- composer.json | 6 +- config/jwt.php | 304 ++++++++++++++++++ .../src/Repositories/AttributeRepository.php | 4 + .../src/Repositories/CategoryRepository.php | 15 +- .../src/Contracts/Criteria/ProductFlat.php | 0 .../Product/src/Helpers/ProductImage.php | 16 +- packages/Webkul/Product/src/Helpers/View.php | 55 ++-- .../Resources/views/products/index.blade.php | 4 +- .../views/products/list/card.blade.php | 18 +- .../product/large-product-placeholder.png | Bin 0 -> 12914 bytes .../product/meduim-product-placeholder.png | Bin 0 -> 7119 bytes .../product/small-product-placeholder.png | Bin 0 -> 2412 bytes 12 files changed, 362 insertions(+), 60 deletions(-) create mode 100644 config/jwt.php delete mode 100644 packages/Webkul/Product/src/Contracts/Criteria/ProductFlat.php create mode 100755 packages/Webkul/Ui/src/Resources/assets/images/product/large-product-placeholder.png create mode 100755 packages/Webkul/Ui/src/Resources/assets/images/product/meduim-product-placeholder.png create mode 100755 packages/Webkul/Ui/src/Resources/assets/images/product/small-product-placeholder.png diff --git a/composer.json b/composer.json index 48c2fa1f2..6ebf4ccf6 100755 --- a/composer.json +++ b/composer.json @@ -9,12 +9,12 @@ "type": "project", "require": { "php": "^7.1.3", + "ext-curl": "*", + "ext-mbstring": "*", "ext-openssl": "*", "ext-pdo": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", "ext-pdo_mysql": "*", - "ext-curl": "*", + "ext-tokenizer": "*", "barryvdh/laravel-dompdf": "^0.8.0@dev", "dimsav/laravel-translatable": "^9.0", "doctrine/dbal": "^2.9@dev", diff --git a/config/jwt.php b/config/jwt.php new file mode 100644 index 000000000..8b7843b6b --- /dev/null +++ b/config/jwt.php @@ -0,0 +1,304 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + + /* + |-------------------------------------------------------------------------- + | JWT Authentication Secret + |-------------------------------------------------------------------------- + | + | Don't forget to set this in your .env file, as it will be used to sign + | your tokens. A helper command is provided for this: + | `php artisan jwt:secret` + | + | Note: This will be used for Symmetric algorithms only (HMAC), + | since RSA and ECDSA use a private/public key combo (See below). + | + */ + + 'secret' => env('JWT_SECRET'), + + /* + |-------------------------------------------------------------------------- + | JWT Authentication Keys + |-------------------------------------------------------------------------- + | + | The algorithm you are using, will determine whether your tokens are + | signed with a random string (defined in `JWT_SECRET`) or using the + | following public & private keys. + | + | Symmetric Algorithms: + | HS256, HS384 & HS512 will use `JWT_SECRET`. + | + | Asymmetric Algorithms: + | RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below. + | + */ + + 'keys' => [ + + /* + |-------------------------------------------------------------------------- + | Public Key + |-------------------------------------------------------------------------- + | + | A path or resource to your public key. + | + | E.g. 'file://path/to/public/key' + | + */ + + 'public' => env('JWT_PUBLIC_KEY'), + + /* + |-------------------------------------------------------------------------- + | Private Key + |-------------------------------------------------------------------------- + | + | A path or resource to your private key. + | + | E.g. 'file://path/to/private/key' + | + */ + + 'private' => env('JWT_PRIVATE_KEY'), + + /* + |-------------------------------------------------------------------------- + | Passphrase + |-------------------------------------------------------------------------- + | + | The passphrase for your private key. Can be null if none set. + | + */ + + 'passphrase' => env('JWT_PASSPHRASE'), + + ], + + /* + |-------------------------------------------------------------------------- + | JWT time to live + |-------------------------------------------------------------------------- + | + | Specify the length of time (in minutes) that the token will be valid for. + | Defaults to 1 hour. + | + | You can also set this to null, to yield a never expiring token. + | Some people may want this behaviour for e.g. a mobile app. + | This is not particularly recommended, so make sure you have appropriate + | systems in place to revoke the token if necessary. + | Notice: If you set this to null you should remove 'exp' element from 'required_claims' list. + | + */ + + 'ttl' => env('JWT_TTL', 60), + + /* + |-------------------------------------------------------------------------- + | Refresh time to live + |-------------------------------------------------------------------------- + | + | Specify the length of time (in minutes) that the token can be refreshed + | within. I.E. The user can refresh their token within a 2 week window of + | the original token being created until they must re-authenticate. + | Defaults to 2 weeks. + | + | You can also set this to null, to yield an infinite refresh time. + | Some may want this instead of never expiring tokens for e.g. a mobile app. + | This is not particularly recommended, so make sure you have appropriate + | systems in place to revoke the token if necessary. + | + */ + + 'refresh_ttl' => env('JWT_REFRESH_TTL', 20160), + + /* + |-------------------------------------------------------------------------- + | JWT hashing algorithm + |-------------------------------------------------------------------------- + | + | Specify the hashing algorithm that will be used to sign the token. + | + | See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL + | for possible values. + | + */ + + 'algo' => env('JWT_ALGO', 'HS256'), + + /* + |-------------------------------------------------------------------------- + | Required Claims + |-------------------------------------------------------------------------- + | + | Specify the required claims that must exist in any token. + | A TokenInvalidException will be thrown if any of these claims are not + | present in the payload. + | + */ + + 'required_claims' => [ + 'iss', + 'iat', + 'exp', + 'nbf', + 'sub', + 'jti', + ], + + /* + |-------------------------------------------------------------------------- + | Persistent Claims + |-------------------------------------------------------------------------- + | + | Specify the claim keys to be persisted when refreshing a token. + | `sub` and `iat` will automatically be persisted, in + | addition to the these claims. + | + | Note: If a claim does not exist then it will be ignored. + | + */ + + 'persistent_claims' => [ + // 'foo', + // 'bar', + ], + + /* + |-------------------------------------------------------------------------- + | Lock Subject + |-------------------------------------------------------------------------- + | + | This will determine whether a `prv` claim is automatically added to + | the token. The purpose of this is to ensure that if you have multiple + | authentication models e.g. `App\User` & `App\OtherPerson`, then we + | should prevent one authentication request from impersonating another, + | if 2 tokens happen to have the same id across the 2 different models. + | + | Under specific circumstances, you may want to disable this behaviour + | e.g. if you only have one authentication model, then you would save + | a little on token size. + | + */ + + 'lock_subject' => true, + + /* + |-------------------------------------------------------------------------- + | Leeway + |-------------------------------------------------------------------------- + | + | This property gives the jwt timestamp claims some "leeway". + | Meaning that if you have any unavoidable slight clock skew on + | any of your servers then this will afford you some level of cushioning. + | + | This applies to the claims `iat`, `nbf` and `exp`. + | + | Specify in seconds - only if you know you need it. + | + */ + + 'leeway' => env('JWT_LEEWAY', 0), + + /* + |-------------------------------------------------------------------------- + | Blacklist Enabled + |-------------------------------------------------------------------------- + | + | In order to invalidate tokens, you must have the blacklist enabled. + | If you do not want or need this functionality, then set this to false. + | + */ + + 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true), + + /* + | ------------------------------------------------------------------------- + | Blacklist Grace Period + | ------------------------------------------------------------------------- + | + | When multiple concurrent requests are made with the same JWT, + | it is possible that some of them fail, due to token regeneration + | on every request. + | + | Set grace period in seconds to prevent parallel request failure. + | + */ + + 'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0), + + /* + |-------------------------------------------------------------------------- + | Cookies encryption + |-------------------------------------------------------------------------- + | + | By default Laravel encrypt cookies for security reason. + | If you decide to not decrypt cookies, you will have to configure Laravel + | to not encrypt your cookie token by adding its name into the $except + | array available in the middleware "EncryptCookies" provided by Laravel. + | see https://laravel.com/docs/master/responses#cookies-and-encryption + | for details. + | + | Set it to true if you want to decrypt cookies. + | + */ + + 'decrypt_cookies' => false, + + /* + |-------------------------------------------------------------------------- + | Providers + |-------------------------------------------------------------------------- + | + | Specify the various providers used throughout the package. + | + */ + + 'providers' => [ + + /* + |-------------------------------------------------------------------------- + | JWT Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to create and decode the tokens. + | + */ + + 'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class, + + /* + |-------------------------------------------------------------------------- + | Authentication Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to authenticate users. + | + */ + + 'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class, + + /* + |-------------------------------------------------------------------------- + | Storage Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to store tokens in the blacklist. + | + */ + + 'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class, + + ], + +]; diff --git a/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php b/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php index 26d79cd65..fbec30646 100755 --- a/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php +++ b/packages/Webkul/Attribute/src/Repositories/AttributeRepository.php @@ -144,6 +144,10 @@ class AttributeRepository extends Repository $data['is_filterable'] = 0; } + if (in_array($data['type'], ['select', 'multiselect', 'boolean'])) { + unset($data['value_per_locale']); + } + return $data; } diff --git a/packages/Webkul/Category/src/Repositories/CategoryRepository.php b/packages/Webkul/Category/src/Repositories/CategoryRepository.php index 476d148c9..ec23041e3 100755 --- a/packages/Webkul/Category/src/Repositories/CategoryRepository.php +++ b/packages/Webkul/Category/src/Repositories/CategoryRepository.php @@ -99,9 +99,18 @@ class CategoryRepository extends Repository */ public function getVisibleCategoryTree($id = null) { - return $id - ? Category::orderBy('position', 'ASC')->where('status', 1)->descendantsOf($id)->toTree() - : Category::orderBy('position', 'ASC')->where('status', 1)->get()->toTree(); + static $categories; + + if ($categories[$id]) + return $categories[$id]; + + if ($id) { + $categories[$id] = Category::orderBy('position', 'ASC')->where('status', 1)->descendantsOf($id)->toTree(); + } else { + $categories[$id] = Category::orderBy('position', 'ASC')->where('status', 1)->get()->toTree(); + } + + return $categories[$id]; } /** diff --git a/packages/Webkul/Product/src/Contracts/Criteria/ProductFlat.php b/packages/Webkul/Product/src/Contracts/Criteria/ProductFlat.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/Webkul/Product/src/Helpers/ProductImage.php b/packages/Webkul/Product/src/Helpers/ProductImage.php index c486f725a..b4769d530 100755 --- a/packages/Webkul/Product/src/Helpers/ProductImage.php +++ b/packages/Webkul/Product/src/Helpers/ProductImage.php @@ -33,10 +33,10 @@ class ProductImage extends AbstractProduct if (! $product || (! $product->parent_id && !count($images))) { $images[] = [ - 'small_image_url' => bagisto_asset('images/product/small-product-placeholder.png'), - 'medium_image_url' => bagisto_asset('images/product/meduim-product-placeholder.png'), - 'large_image_url' => bagisto_asset('images/product/large-product-placeholder.png'), - 'original_image_url' => bagisto_asset('images/product/large-product-placeholder.png'), + 'small_image_url' => asset('vendor/webkul/ui/assets/images/product/small-product-placeholder.png'), + 'medium_image_url' => asset('vendor/webkul/ui/assets/images/product/meduim-product-placeholder.png'), + 'large_image_url' => asset('vendor/webkul/ui/assets/images/product/large-product-placeholder.png'), + 'original_image_url' => asset('vendor/webkul/ui/assets/images/product/large-product-placeholder.png') ]; } @@ -61,10 +61,10 @@ class ProductImage extends AbstractProduct ]; } else { $image = [ - 'small_image_url' => bagisto_asset('images/product/small-product-placeholder.png'), - 'medium_image_url' => bagisto_asset('images/product/meduim-product-placeholder.png'), - 'large_image_url' => bagisto_asset('images/product/large-product-placeholder.png'), - 'original_image_url' => bagisto_asset('images/product/large-product-placeholder.png'), + 'small_image_url' => asset('vendor/webkul/ui/assets/images/product/small-product-placeholder.png'), + 'medium_image_url' => asset('vendor/webkul/ui/assets/images/product/meduim-product-placeholder.png'), + 'large_image_url' => asset('vendor/webkul/ui/assets/images/product/large-product-placeholder.png'), + 'original_image_url' => asset('vendor/webkul/ui/assets/images/product/large-product-placeholder.png'), ]; } diff --git a/packages/Webkul/Product/src/Helpers/View.php b/packages/Webkul/Product/src/Helpers/View.php index 9fd300625..2c4904d24 100755 --- a/packages/Webkul/Product/src/Helpers/View.php +++ b/packages/Webkul/Product/src/Helpers/View.php @@ -14,58 +14,43 @@ class View extends AbstractProduct { $data = []; - $attributes = $product->attribute_family->custom_attributes; + $attributes = $product->attribute_family->custom_attributes()->where('attributes.is_visible_on_front', 1)->get(); $attributeOptionReposotory = app('Webkul\Attribute\Repositories\AttributeOptionRepository'); foreach ($attributes as $attribute) { if ($attribute->type == 'boolean') { - $value = $product->{$attribute->code}; - if ($attribute->is_visible_on_front ) { - if ($value == 1) { - $value = 'Yes'; - } else { - $value = 'No'; - } + $value = $product->{$attribute->code} ? 'Yes' : 'No'; - $data[] = [ - 'code' => $attribute->code, - 'label' => $attribute->name, - 'value' => $value, - 'admin_name' => $attribute->admin_name, - ]; - } - } else if ($attribute->is_visible_on_front && $product->{$attribute->code}) { + $data[] = [ + 'code' => $attribute->code, + 'label' => $attribute->name, + 'value' => $value, + 'admin_name' => $attribute->admin_name, + ]; + } else if ($product->{$attribute->code}) { $value = $product->{$attribute->code}; if ($attribute->type == 'select') { $attributeOption = $attributeOptionReposotory->find($value); if ($attributeOption) { - $value = $attributeOption->translate(app()->getLocale()); - if ($value) { - $value = $value->label; - } + $value = $attributeOption->label; } - } + } else if ($attribute->type == 'multiselect') { + $optionIds = explode(",", $value); - if ($attribute->type == 'multiselect') { - $values = explode(",", $value); + if (count($optionIds)) { + $attributeOptions = $attributeOptionReposotory->findWhereIn('id', $optionIds); - $result = []; - foreach ($values as $value) { - $attributeOption = $attributeOptionReposotory->find($value); - - if ($attributeOption) { - $value = $attributeOption->translate(app()->getLocale()); - if ($value) { - $value = $value->label; - $result[] = $value; + foreach ($attributeOptions as $attributeOption) { + if ($attributeOption && $attributeOption->label) { + $result[] = $attributeOption->label; } } - } - $value = implode(", ", $result); + $value = implode(", ", $result); + } } $data[] = [ @@ -73,7 +58,7 @@ class View extends AbstractProduct 'label' => $attribute->name, 'value' => $value, 'admin_name' => $attribute->admin_name, - ]; + ]; } } diff --git a/packages/Webkul/Shop/src/Resources/views/products/index.blade.php b/packages/Webkul/Shop/src/Resources/views/products/index.blade.php index b5ccd5c11..a144e1cf6 100755 --- a/packages/Webkul/Shop/src/Resources/views/products/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/products/index.blade.php @@ -49,7 +49,7 @@
@foreach ($products as $productFlat) - @include ('shop::products.list.card', ['product' => $productFlat->product]) + @include ('shop::products.list.card', ['productFlat' => $productFlat]) @endforeach
@@ -57,7 +57,7 @@
@foreach ($products as $productFlat) - @include ('shop::products.list.card', ['product' => $productFlat->product]) + @include ('shop::products.list.card', ['productFlat' => $productFlat]) @endforeach
diff --git a/packages/Webkul/Shop/src/Resources/views/products/list/card.blade.php b/packages/Webkul/Shop/src/Resources/views/products/list/card.blade.php index 03eada776..24e19e356 100755 --- a/packages/Webkul/Shop/src/Resources/views/products/list/card.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/products/list/card.blade.php @@ -1,19 +1,19 @@ -{!! view_render_event('bagisto.shop.products.list.card.before', ['product' => $product]) !!} +{!! view_render_event('bagisto.shop.products.list.card.before', ['product' => $productFlat->product]) !!}
@inject ('productImageHelper', 'Webkul\Product\Helpers\ProductImage') - getProductBaseImage($product); ?> + getProductBaseImage($productFlat->product); ?> - @if ($product->new) + @if ($productFlat->new)
{{ __('shop::app.products.new') }}
@endif @@ -21,18 +21,18 @@
- @include ('shop::products.price', ['product' => $product]) + @include ('shop::products.price', ['product' => $productFlat->product]) - @include('shop::products.add-buttons') + @include('shop::products.add-buttons', ['product' => $productFlat->product])
-{!! view_render_event('bagisto.shop.products.list.card.after', ['product' => $product]) !!} \ No newline at end of file +{!! view_render_event('bagisto.shop.products.list.card.after', ['product' => $productFlat->product]) !!} \ No newline at end of file diff --git a/packages/Webkul/Ui/src/Resources/assets/images/product/large-product-placeholder.png b/packages/Webkul/Ui/src/Resources/assets/images/product/large-product-placeholder.png new file mode 100755 index 0000000000000000000000000000000000000000..e839910ccb43d249c2259100efa6929803ad7bd1 GIT binary patch literal 12914 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 S0sln8pnuWm!uxX$_x=N20pnc& literal 0 HcmV?d00001 diff --git a/packages/Webkul/Ui/src/Resources/assets/images/product/meduim-product-placeholder.png b/packages/Webkul/Ui/src/Resources/assets/images/product/meduim-product-placeholder.png new file mode 100755 index 0000000000000000000000000000000000000000..0aa66dc5200c0a9b9e96da022f344e7db1004be2 GIT binary patch literal 7119 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 VR;Si}W&EK7=xP~hR;Xj~{|2acysrQN literal 0 HcmV?d00001 diff --git a/packages/Webkul/Ui/src/Resources/assets/images/product/small-product-placeholder.png b/packages/Webkul/Ui/src/Resources/assets/images/product/small-product-placeholder.png new file mode 100755 index 0000000000000000000000000000000000000000..8526a85f5f5735a9ce2894e304d9ae3dc4fdc259 GIT binary patch literal 2412 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 literal 0 HcmV?d00001