determineCategoriesRoutes

determineCategoriesRoutes

我的建议是创建一个CategoryRouteService类,该类将注册为单例,以使数据库查询尽可能少.可能是这样的:class CategoryRouteService{ private $routes = []; public function __construct() { $this->determineCategoriesRoutes(); } public function getRoute(Category $category) { return $this->routes[$category->id]; } private function determineCategoriesRoutes() { $categories = Category::all()->keyBy('id'); foreach ($categories as $id => $category) { $slugs = $this->determineCategorySlugs($category, $categories); if (count($slugs) === 1) { $this->routes[$id] = url('/p/' . $slugs[0]); } else { $this->routes[$id] = url('/' . implode('/', $slugs)); } } } private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = []) { array_unshift($slugs, $category->slug); if (!is_null($category->parent_id)) { $slugs = $this->determineCategorySlugs($categories[$category->parent_id], $categories, $slugs); } return $slugs; }}现在,正如我之前所说,您需要服务提供商来注册此服务.它应该看起来像这样:class CategoryServiceProvider{ public function register() { $this->app->singleton(CategoryRouteService::class, function ($app) { // At this point the categories routes will be determined. // It happens only one time even if you call the service multiple times through the container. return new CategoryRouteService(); }); }}此服务提供商必须添加到应用程序配置文件中. Category模型可以具有定义route属性的方法:class Category extends Model{ public function getRouteAttribute() { $categoryRouteService = app(CategoryRouteService::class); return $categoryRouteService->getRoute($this); } /** Your relationships methods **/}最后,只需使用$category->route,就可以在刀片视图中使用它.@foreach($post->categories as $category) <a class="post-cat" href="{{$category->route}}">{{$category->title}}</a>@endforeach请注意,可能还有其他解决方案比这更好.我只是在没有过多思考的情况下碰到了这一点.另外,上面的代码尚未经过测试,因此请注意,可能需要进行一些较小的更改才能使其正常工作.I have 3 level deep categories in my laravel application likeParent - Child One -- Child TwoWhen I use this nested categories in different parts such as menu, posts details etc. everything is just fine but recently I came cross an issue and I need guide to solve it.The issueIf any of my posts includes child one or child two level category it's a bit hard to provide correct route path for it, EXAMPLE:Parent route : site.com/p/slugChild one route: site.com/parent_slug/childOne_slugChild two route: site.com/parent_slug/childOne_slug/childTwo_slugcreating this much if statement in blade to make sure we get the right route for the right categories to me doesn't seem right. I was thinking about model function which returns final route depend on category parenting level in database but I wasn't sure if it's possible or not? and if it is, how?QuestionIs it possible I pass category routes to the categories from model?How to do that?CodeCategory modelprotected $fillable = [ 'title', 'slug', 'thumbnail', 'publish','mainpage', 'parent_id', 'color', 'template' ]; public function posts(){ return $this->belongsToMany(Post::class, 'post_categories'); } public function parent() { return $this->belongsTo(Category::class, 'parent_id'); } public function children() { return $this->hasMany(Category::class, 'parent_id'); }this is how currently i'm getting my posts categories:@foreach($post->categories as $category) <a class="post-cat" href="#">{{$category->title}}</a>@endforeachAny idea?UPDATEWell I solved it :-D here is the code I've madepublic function getCatSlug(){ if($this->parent_id != ''){ //child one if($this->parent->parent_id != ''){ //child two if($this->parent->parent->parent_id != ''){ //child three return $this->parent->parent->parent->slug. '/'. $this->parent->parent->slug. '/'. $this->parent->slug. '/'. $this->slug; } return $this->parent->parent->slug. '/'. $this->parent->slug. '/'. $this->slug; } return $this->parent->slug. '/'. $this->slug; } return $this->slug; }This does exactly what I needed it return slugs by orders like parent/child1/child2Issuethe issue here is now routing this dynamic path as the result of this function I can now have any deep level of path and this needs to be dynamic in routes as well.Routemy current route is like:Route::get('/category/{slug}', 'Front\CategoryController@parent')->name('categoryparent');which returns this path:site.com/category/parentbut it doesn't return:site.com/category/parent/child_onesite.com/category/parent/child_one/child_twoControllerpublic function parent($slug){ $category = Category::where('slug', $slug)->with('children')->first(); $category->addView(); $posts = $category->posts()->paginate(8); return view('front.categories.single', compact('category','posts'));}any idea?Update 2based on Matei Mihai answer I've made custom classes in App/Helpers folder with details below:CategoryRouteService.php<?phpnamespace App\Helpers;use App\Category;class CategoryRouteService{ private $routes = []; public function __construct() { $this->determineCategoriesRoutes(); } public function getRoute(Category $category) { return $this->routes[$category->id]; } private function determineCategoriesRoutes() { $categories = Category::all()->keyBy('id'); foreach ($categories as $id => $category) { $slugs = $this->determineCategorySlugs($category, $categories); if (count($slugs) === 1) { $this->routes[$id] = url('p/' . $slugs[0]); } else { $this->routes[$id] = url('/' . implode('/', $slugs)); } } } private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = []) { array_unshift($slugs, $category->slug); if (!is_null($category->parent_id)) { $slugs = $this->determineCategorySlugs($categories[$category->parent_id], $categories, $slugs); } return $slugs; }}and CategoryServiceProvider.php<?phpnamespace App\Helpers;use App\Helpers\CategoryRouteService;class CategoryServiceProvider{ public function register() { $this->app->singleton(CategoryRouteService::class, function ($app) { // At this point the categories routes will be determined. // It happens only one time even if you call the service multiple times through the container. return new CategoryRouteService(); }); }}then I registered my provider to composer.json file like:"autoload": { "classmap": [ "database/seeds", "database/factories" ], "psr-4": { "App\\": "app/" }, "files": [ "app/helpers/CategoryServiceProvider.php" //added here ] },I also dumped autoloads and added this to my Category modeluse App\Helpers\CategoryRouteService;public function getRouteAttribute(){ $categoryRouteService = app(CategoryRouteService::class); return $categoryRouteService->getRoute($this);}then I used {{$category->route}} as my categries href attribute and I got this:Argument 2 passed to App\Helpers\CategoryRouteService::determineCategorySlugs() must be an instance of App\Helpers\Collection, instance of Illuminate\Database\Eloquent\Collection givenwhich is refers to:private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = []) {ideas? 解决方案 It is possible, but you must take care of the script performance because it could end up having a lot of DB queries done to determine each category route.My recommendation would be to create a CategoryRouteService class which will be registered as singleton to keep the database queries as low as possible. It could be something like:class CategoryRouteService{ private $routes = []; public function __construct() { $this->determineCategoriesRoutes(); } public function getRoute(Category $category) { return $this->routes[$category->id]; } private function determineCategoriesRoutes() { $categories = Category::all()->keyBy('id'); foreach ($categories as $id => $category) { $slugs = $this->determineCategorySlugs($category, $categories); if (count($slugs) === 1) { $this->routes[$id] = url('/p/' . $slugs[0]); } else { $this->routes[$id] = url('/' . implode('/', $slugs)); } } } private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = []) { array_unshift($slugs, $category->slug); if (!is_null($category->parent_id)) { $slugs = $this->determineCategorySlugs($categories[$category->parent_id], $categories, $slugs); } return $slugs; }}Now as I said before, you need a service provider to register this service. It should look like this:class CategoryServiceProvider{ public function register() { $this->app->singleton(CategoryRouteService::class, function ($app) { // At this point the categories routes will be determined. // It happens only one time even if you call the service multiple times through the container. return new CategoryRouteService(); }); }}This service provider must be added in the app configuration file.The Category model could have a method which defines the route attribute:class Category extends Model{ public function getRouteAttribute() { $categoryRouteService = app(CategoryRouteService::class); return $categoryRouteService->getRoute($this); } /** Your relationships methods **/}Finally, you can use it in your blade views simply by using $category->route.@foreach($post->categories as $category) <a class="post-cat" href="{{$category->route}}">{{$category->title}}</a>@endforeachPlease note that there could be other solutions better than this. I just came across this one without thinking too much. Also, the code above was not tested so please be aware that it might need some minor changes to make it work properly. 这篇关于laravel中的动态类别级别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-04 16:48