diff --git a/packages/Webkul/Category/src/Repositories/CategoryRepository.php b/packages/Webkul/Category/src/Repositories/CategoryRepository.php index e6380d55f..21fd1c686 100755 --- a/packages/Webkul/Category/src/Repositories/CategoryRepository.php +++ b/packages/Webkul/Category/src/Repositories/CategoryRepository.php @@ -151,6 +151,24 @@ class CategoryRepository extends Repository ); } + /** + * @param string $urlPath + * + * @return mixed + */ + public function findByPathOrFail(string $urlPath) + { + $category = $this->model->whereTranslation('url_path', $urlPath)->first(); + + if ($category) { + return $category; + } + + throw (new ModelNotFoundException)->setModel( + get_class($this->model), $urlPath + ); + } + /** * @param array $data * @param $id diff --git a/packages/Webkul/Customer/src/Http/Controllers/WishlistController.php b/packages/Webkul/Customer/src/Http/Controllers/WishlistController.php index 24790355f..590bbebb6 100755 --- a/packages/Webkul/Customer/src/Http/Controllers/WishlistController.php +++ b/packages/Webkul/Customer/src/Http/Controllers/WishlistController.php @@ -166,14 +166,14 @@ class WishlistController extends Controller } else { session()->flash('info', trans('shop::app.wishlist.option-missing')); - return redirect()->route('shop.products.index', $wishlistItem->product->url_key); + return redirect()->route('shop.productOrCategory.index', $wishlistItem->product->url_key); } return redirect()->back(); } catch (\Exception $e) { session()->flash('warning', $e->getMessage()); - return redirect()->route('shop.products.index', ['slug' => $wishlistItem->product->url_key]); + return redirect()->route('shop.productOrCategory.index', ['slug' => $wishlistItem->product->url_key]); } } diff --git a/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194541_add_column_url_path_to_category_translations.php b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194541_add_column_url_path_to_category_translations.php new file mode 100644 index 000000000..167f43056 --- /dev/null +++ b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194541_add_column_url_path_to_category_translations.php @@ -0,0 +1,32 @@ +string('url_path'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('category_translations', function (Blueprint $table) { + $table->dropColumn('url_path'); + }); + } +} diff --git a/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194608_add_stored_function_to_get_url_path_of_category.php b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194608_add_stored_function_to_get_url_path_of_category.php new file mode 100644 index 000000000..1470a4b43 --- /dev/null +++ b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194608_add_stored_function_to_get_url_path_of_category.php @@ -0,0 +1,65 @@ += parent._lft + AND node._rgt <= parent._rgt + AND node.id = categoryId + AND parent.id <> 1 + GROUP BY + node.id; + + IF urlPath IS NULL + THEN + SET urlPath = (SELECT slug FROM category_translations WHERE category_translations.category_id = categoryId); + END IF; + ELSE + SET urlPath = ''; + END IF; + + RETURN urlPath; + END; +SQL; + + DB::unprepared($functionSQL); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + DB::unprepared('DROP FUNCTION IF EXISTS `get_url_path_of_category`;'); + } +} diff --git a/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194627_add_trigger_to_category_translations.php b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194627_add_trigger_to_category_translations.php new file mode 100644 index 000000000..8004d61c8 --- /dev/null +++ b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194627_add_trigger_to_category_translations.php @@ -0,0 +1,99 @@ +getTriggerBody('insert'); + $insertTrigger = <<< SQL + CREATE TRIGGER %s + BEFORE INSERT ON category_translations + FOR EACH ROW + BEGIN + $insertTriggerBody + END; +SQL; + + $updateTriggerBody = $this->getTriggerBody(); + $updateTrigger = <<< SQL + CREATE TRIGGER %s + BEFORE UPDATE ON category_translations + FOR EACH ROW + BEGIN + $updateTriggerBody + END; +SQL; + + DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_INSERT)); + DB::unprepared(sprintf($insertTrigger, self::TRIGGER_NAME_INSERT)); + + DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_UPDATE)); + DB::unprepared(sprintf($updateTrigger, self::TRIGGER_NAME_UPDATE)); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_INSERT)); + DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_UPDATE)); + } + + /** + * Returns trigger body as string based on type ('update' or 'insert'). + * + * @param string $type + * + * @return string + */ + private function getTriggerBody(string $type = 'update'): string + { + $addOnInsert = ($type === 'update') ? '' : <<< SQL + ELSE + SELECT CONCAT(urlPath, '/', NEW.slug) INTO urlPath; +SQL; + + return <<< SQL + DECLARE urlPath varchar(255); + + IF NEW.category_id != 1 + THEN + SELECT + GROUP_CONCAT(parent_translations.slug SEPARATOR '/') INTO urlPath + FROM + categories AS node, + categories AS parent + JOIN category_translations AS parent_translations ON parent.id = parent_translations.category_id + WHERE + node._lft >= parent._lft + AND node._rgt <= parent._rgt + AND node.id = NEW.category_id + AND parent.id <> 1 + GROUP BY + node.id; + + IF urlPath IS NULL + THEN + SET urlPath = NEW.slug; + $addOnInsert + END IF; + + SET NEW.url_path = urlPath; + END IF; +SQL; + } +} diff --git a/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194648_add_url_path_to_existing_category_translations.php b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194648_add_url_path_to_existing_category_translations.php new file mode 100644 index 000000000..accaf674f --- /dev/null +++ b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194648_add_url_path_to_existing_category_translations.php @@ -0,0 +1,44 @@ += parent._lft + AND node._rgt <= parent._rgt + AND node.id = :category_id + AND node.id <> 1 + AND parent.id <> 1 + GROUP BY + node.id +SQL; + + $categoryTranslationsTableName = app(CategoryTranslation::class)->getTable(); + + foreach (DB::table($categoryTranslationsTableName)->get() as $categoryTranslation) { + $urlPathQueryResult = DB::selectOne($sql, ['category_id' => $categoryTranslation->category_id]); + $url_path = $urlPathQueryResult ? $urlPathQueryResult->url_path : ''; + + DB::table($categoryTranslationsTableName) + ->where('id', $categoryTranslation->id) + ->update(['url_path' => $url_path]); + } + } +} diff --git a/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194703_add_trigger_to_categories.php b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194703_add_trigger_to_categories.php new file mode 100644 index 000000000..e25243d64 --- /dev/null +++ b/packages/Webkul/Shop/src/Database/Migrations/2019_11_21_194703_add_trigger_to_categories.php @@ -0,0 +1,66 @@ +productRepository->find($id); - return redirect()->route('shop.products.index', ['slug' => $product->url_key]); + return redirect()->route('shop.productOrCategory.index', ['slug' => $product->url_key]); } return redirect()->back(); diff --git a/packages/Webkul/Shop/src/Http/Controllers/CategoryController.php b/packages/Webkul/Shop/src/Http/Controllers/CategoryController.php index 03d428067..69defe0a9 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/CategoryController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/CategoryController.php @@ -38,17 +38,4 @@ class CategoryController extends Controller $this->_config = request('_config'); } - - /** - * Display a listing of the resource. - * - * @param string $slug - * @return \Illuminate\View\View - */ - public function index($slug) - { - $category = $this->categoryRepository->findBySlugOrFail($slug); - - return view($this->_config['view'], compact('category')); - } } diff --git a/packages/Webkul/Shop/src/Http/Controllers/ProductController.php b/packages/Webkul/Shop/src/Http/Controllers/ProductController.php index ef6144581..2f24b78e8 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/ProductController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/ProductController.php @@ -79,21 +79,6 @@ class ProductController extends Controller $this->_config = request('_config'); } - /** - * Display a listing of the resource. - * - * @param string $slug - * @return \Illuminate\View\View - */ - public function index($slug) - { - $product = $this->productRepository->findBySlugOrFail($slug); - - $customer = auth()->guard('customer')->user(); - - return view($this->_config['view'], compact('product', 'customer')); - } - /** * Download image or file * diff --git a/packages/Webkul/Shop/src/Http/Controllers/ProductsCategoriesProxyController.php b/packages/Webkul/Shop/src/Http/Controllers/ProductsCategoriesProxyController.php new file mode 100644 index 000000000..7abca8acb --- /dev/null +++ b/packages/Webkul/Shop/src/Http/Controllers/ProductsCategoriesProxyController.php @@ -0,0 +1,92 @@ +categoryRepository = $categoryRepository; + $this->productRepository = $productRepository; + + $this->_config = request('_config'); + } + + /** + * Display a listing of the resource which can be a category or a product. + * + * + * @param string $slug + * + * @return \Illuminate\View\View + */ + public function index(string $slug) + { + $slug = rtrim($slug, '/ '); + + if (preg_match('/^([a-z-]+\/?)+$/', $slug)) { + + if (DB::table(app(CategoryTranslation::class)->getTable()) + ->where('url_path', '=', $slug) + ->exists() + ) { + + $category = $this->categoryRepository->findByPathOrFail($slug); + + return view($this->_config['category_view'], compact('category')); + } + + if (DB::table(app(ProductFlat::class)->getTable()) + ->where('url_key', '=', $slug) + ->exists() + ) { + $product = $this->productRepository->findBySlugOrFail($slug); + + $customer = auth()->guard('customer')->user(); + + return view($this->_config['product_view'], compact('product', 'customer')); + } + + } else { + throw new NotFoundHttpException(); + } + } +} \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Http/routes.php b/packages/Webkul/Shop/src/Http/routes.php index 1eb433e8e..c3c8601a3 100755 --- a/packages/Webkul/Shop/src/Http/routes.php +++ b/packages/Webkul/Shop/src/Http/routes.php @@ -13,11 +13,6 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function //unsubscribe Route::get('/unsubscribe/{token}', 'Webkul\Shop\Http\Controllers\SubscriptionController@unsubscribe')->name('shop.unsubscribe'); - //Store front header nav-menu fetch - Route::get('/categories/{slug}', 'Webkul\Shop\Http\Controllers\CategoryController@index')->defaults('_config', [ - 'view' => 'shop::products.index' - ])->name('shop.categories.index'); - //Store front search Route::get('/search', 'Webkul\Shop\Http\Controllers\SearchController@index')->defaults('_config', [ 'view' => 'shop::search.search' @@ -89,11 +84,6 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function //Shop buynow button action Route::get('move/wishlist/{id}', 'Webkul\Shop\Http\Controllers\CartController@moveToWishlist')->name('shop.movetowishlist'); - //Show Product Details Page(For individually Viewable Product) - Route::get('/products/{slug}', 'Webkul\Shop\Http\Controllers\ProductController@index')->defaults('_config', [ - 'view' => 'shop::products.view' - ])->name('shop.products.index'); - Route::get('/downloadable/download-sample/{type}/{id}', 'Webkul\Shop\Http\Controllers\ProductController@downloadSample')->name('shop.downloadable.download_sample'); // Show Product Review Form @@ -307,5 +297,13 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function Route::get('page/{slug}', 'Webkul\CMS\Http\Controllers\Shop\PagePresenterController@presenter')->name('shop.cms.page'); + Route::get('{slug}', \Webkul\Shop\Http\Controllers\ProductsCategoriesProxyController::class . '@index') + ->defaults('_config', [ + 'product_view' => 'shop::products.view', + 'category_view' => 'shop::products.index' + ]) + ->where('slug', '^([a-z-]+\/?)+$') + ->name('shop.productOrCategory.index'); + Route::fallback('Webkul\Shop\Http\Controllers\HomeController@notFound'); }); diff --git a/packages/Webkul/Shop/src/Providers/ShopServiceProvider.php b/packages/Webkul/Shop/src/Providers/ShopServiceProvider.php index e97fd1d9d..06c0d1cee 100755 --- a/packages/Webkul/Shop/src/Providers/ShopServiceProvider.php +++ b/packages/Webkul/Shop/src/Providers/ShopServiceProvider.php @@ -25,6 +25,8 @@ class ShopServiceProvider extends ServiceProvider */ public function boot(Router $router) { + $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + $this->loadRoutesFrom(__DIR__ . '/../Http/routes.php'); $this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'shop'); diff --git a/packages/Webkul/Shop/src/Resources/views/layouts/footer/footer.blade.php b/packages/Webkul/Shop/src/Resources/views/layouts/footer/footer.blade.php index a9ecdb554..fd541a7e9 100755 --- a/packages/Webkul/Shop/src/Resources/views/layouts/footer/footer.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/layouts/footer/footer.blade.php @@ -18,7 +18,7 @@ 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 c0d9f588c..6ccb3fdee 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 @@ -13,7 +13,7 @@ @endif
- +
@@ -21,7 +21,7 @@
- + {{ $product->name }} diff --git a/packages/Webkul/Shop/src/Resources/views/products/reviews/create.blade.php b/packages/Webkul/Shop/src/Resources/views/products/reviews/create.blade.php index ad6b8365b..0ce797b32 100755 --- a/packages/Webkul/Shop/src/Resources/views/products/reviews/create.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/products/reviews/create.blade.php @@ -15,13 +15,13 @@ getProductBaseImage($product); ?> diff --git a/packages/Webkul/Shop/src/Resources/views/products/reviews/index.blade.php b/packages/Webkul/Shop/src/Resources/views/products/reviews/index.blade.php index 79a519a4b..329fbdff4 100755 --- a/packages/Webkul/Shop/src/Resources/views/products/reviews/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/products/reviews/index.blade.php @@ -17,13 +17,13 @@
diff --git a/tests/Browser/ProductCategoryTest.php b/tests/Browser/ProductCategoryTest.php index 4c8b2658b..6717e2941 100644 --- a/tests/Browser/ProductCategoryTest.php +++ b/tests/Browser/ProductCategoryTest.php @@ -41,7 +41,7 @@ class ProductCategoryTest extends DuskTestCase } $this->browse(function (Browser $browser) use($testSlug, $testProduct) { - $browser->visit(route('shop.categories.index', $testSlug)); + $browser->visit(route('shop.productOrCategory.index', $testSlug)); $browser->assertSeeLink($testProduct[0]['name']); $browser->pause(5000); });