http://example.com/catalog/category/sub-category .parent_id attribute and the parent relation. class Category extends Model { public function parent() { return $this->belongsTo(self::class); } } slug - a stub that reflects the section in the URL. It can be generated from the name, or specified by the user manually. Most importantly, the stub must pass the alphadash validation alphadash (that is, consist of letters, numbers, and signs, _ ), and also be unique within the parent section. For the latter, it is enough to create a unique index in the database (parent_id, slug) . public function getUrl() { $url = $this->slug; $category = $this; while ($category = $category->parent) { $url = $category->slug.'/'.$url; } return 'catalog/'.$url; } $router->get('catalog/{category}', ...); http://example.com/catalog/category . The route will work. Now this link: http://example.com/catalog/category/sub-category . The route will no longer work, because backslash is a parameter delimiter. Hmm, then add another parameter and make it optional: $router->get('catalog/{category}/{subcategory?}', ...); category identifier, then, if specified, the subcategory subsection, etc. All this causes inconvenience and server load, the number of requests is proportional to the number of subsections. composer require kalnoy/nestedset Schema::table('categories', function (Blueprint $table) { $table->unsignedInteger('_lft'); $table->unsignedInteger('_rgt'); }); parent and children relations, if they have been set, and also add a trait Kalnoy\Nestedset\NodeTrait . After the upgrade, our model looks like this: class Category extends Model { use Kalnoy\Nestedset\NodeTrait; } _lft and _rgt not filled in, so that everything _rgt , the final touch remains: Category::fixTree(); parent_id " the tree based on the parent_id attribute. public function getUrl() { // $slugs = $this->ancestors()->lists('slug'); // $slugs[] = $this->slug; // return 'catalog/'.implode('/', $slugs); } $router->get('catalog/{path}', 'CategoriesController@show') ->where('path', '[a-zA-Z0-9/_-]+'); {path} parameter can contain not only the usual string, but also a backslash. Thus, this parameter immediately captures the entire path that follows the control word catalog . public function show($path) { $path = explode('/', $path); } - Category -- Sub category --- Sub sub category - category -- category/sub-category --- category/sub-category/sub-sub-category public function show($path) { $category = Category::where('path', '=', $path)->firstOrFail(); } // public function generatePath() { $slugs = $this->ancestors()->lists('slug'); $slugs[] = $this->slug; $this->path = implode('/', $slugs); return $this; } // public function getUrl() { return 'catalog/'.$this->path; } -/- . Therefore, the path generation can be further optimized: public function generatePath() { $slug = $this->slug; $this->path = $this->isRoot() ? $slug : $this->parent->path.'/'.$slug; return $this; } public function updateDescendantsPaths() { // $descendants = $this->descendants()->defaultOrder()->get(); // parent children $descendants->push($this)->linkNodes()->pop(); foreach ($descendants as $model) { $model->generatePath()->save(); } } defaultOrder here applies tree sorting. Its meaning is that in the list each section will stand after its ancestor . The path construction algorithm uses the parent, so it is necessary that the parent update its path before the path of any of its descendants is updated.parent relationship, which is used in the path generation algorithm. If you do not use this optimization, each generatePath call will execute a query to get the value of the parent relationship. In this case, linkNodes works with the collection of sections and does not make any queries to the database. Therefore, for this to work for the immediate children of the current section, you need to add it to the collection. We add the current section, we connect all sections among themselves and we remove it.slug or parent_id attributes have changed. If changed, we call the generatePath method;path attribute has changed, and if it has changed, call the updateDescendantsPaths method. protected static function boot() { static::saving(function (self $model) { if ($model->isDirty('slug', 'parent_id')) { $model->generatePath(); } }); static::saved(function (self $model) { // , // , .. static $updating = false; if ( ! $updating && $model->isDirty('path')) { $updating = true; $model->updateDescendantsPaths(); $updating = false; } }); } http://example.com/catalog/category/sub-catagory/product . The main problem here is to form the correct route.(category_id, slug) . // $router->get('catalog/{path}', function ($path) { return 'category = '.$path; })->where('path', '[a-zA-Z0-9\-/_]+'); // $router->get('catalog/{category}/{product}', function ($category, $product) { return 'category = '.$category.'<br>product = '.$product; })->where('category', '[a-zA-Z0-9\-/_]+'); category = category/sub-category/product catalog keyword. Need to swap routes. Then we get: category = category/sub-category product = product http://example.com/catalog/category/sub-category . We get the following: category = category product = sub-category http://example.com/catalog/category/sub-category/123-product{product} : $router->get(...)->where('product', '[0-9]+-[a-zA-Z0-9_-]+'); $product->slug = $product->id.'-'.str_slug($product->name); $url = 'catalog/'.$product->category->path.'/'.$product->slug; public function show($categoryPath, $productSlug) { // $category = Category::where('path', '=', $categoryPath)->firstOrFail(); // $product = $category->products() ->where('slug', '=', $productSlug) ->firstOrFail(); } p- :http://example.com/catalog/category/sub-category/p-product $router->get('catalog/{category}/p-{product}', ...); $product->slug = str_slug($product->name); $url = 'catalog/'.$product->category->path.'/p-'.$product->slug; class Url extends Model { // public function model() { return $this->morphTo(); } } $router->get('catalog/{path}', function ($path) { $url = Url::findOrFail($path); // $model = $url->model; if ($model instanceof Product) { return $this->renderProduct($model); } return $this->renderCategory($model); }) ->where('path', '[a-zA-Z0-9\-/_]+'); Url model has a polymorphic relationship with other models and stores full paths on them. What it gives:kalnoy/nestedset , as well as approaches to forming links to sections and products in the case where the nesting depth of sections is not limited.Source: https://habr.com/ru/post/279233/
All Articles