【发布时间】:2019-04-05 11:41:54
【问题描述】:
我的 laravel 应用程序中有 3 个级别的深度类别,例如
Parent
- Child One
-- Child Two
当我在菜单、帖子详细信息等不同部分使用此嵌套类别时,一切都很好,但最近我遇到了一个问题,我需要指导来解决它。
问题
如果我的任何帖子包含child one 或child two 级别类别,则很难为其提供正确的路线路径,例如:
Parent route : site.com/p/slug
Child one route: site.com/parent_slug/childOne_slug
Child two route: site.com/parent_slug/childOne_slug/childTwo_slug
在刀片中创建这么多 if 语句以确保我们为正确的类别获得正确的路线对我来说似乎不正确。我正在考虑返回最终路线的模型函数取决于数据库中的类别育儿级别,但我不确定它是否可能?如果是,如何?
问题
- 是否可以将类别路由传递给模型中的类别?
- 怎么做?
代码
Category model
protected $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');
}
这是我目前获取帖子类别的方式:
@foreach($post->categories as $category)
<a class="post-cat" href="#">{{$category->title}}</a>
@endforeach
有什么想法吗?
更新
好吧,我解决了:-D 这是我制作的代码
public 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;
}
这正是我所需要的,它通过像parent/child1/child2 这样的命令返回蛞蝓
问题
这里的问题现在是路由这个动态路径,因为这个函数的结果我现在可以有任何深层路径,这也需要在路由中是动态的。
路线
我现在的路线是这样的:
Route::get('/category/{slug}', 'Front\CategoryController@parent')->name('categoryparent');
返回此路径:
site.com/category/parent
但它没有返回:
site.com/category/parent/child_one
site.com/category/parent/child_one/child_two
Controller
public 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'));
}
有什么想法吗?
更新 2
基于Matei Mihai 的答案,我在App/Helpers 文件夹中创建了自定义类,详细信息如下:
CategoryRouteService.php
<?php
namespace 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;
}
}
和CategoryServiceProvider.php
<?php
namespace 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();
});
}
}
然后我将我的提供程序注册到composer.json 文件,例如:
"autoload": {
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/helpers/CategoryServiceProvider.php" //added here
]
},
我还转储了自动加载并将其添加到我的 Category 模型中
use App\Helpers\CategoryRouteService;
public function getRouteAttribute()
{
$categoryRouteService = app(CategoryRouteService::class);
return $categoryRouteService->getRoute($this);
}
然后我使用 {{$category->route}} 作为我的类别 href 属性,我得到了这个:
Argument 2 passed to App\Helpers\CategoryRouteService::determineCategorySlugs() must be an instance of App\Helpers\Collection, instance of Illuminate\Database\Eloquent\Collection given
指的是:
private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = [])
{
想法?
【问题讨论】:
-
模型方法将是解决此问题的好方法。诀窍是递归查找父类别(及其父类别等),直到您发现您已经找到顶级类别。然后,您可以将找到的每个类别的 slug 传递到您的路线中。如果您需要进一步的帮助,请试一试并发布您的代码。在这种情况下查看您的路线定义也会很有帮助,如果您可以发布它 - 这将使我们能够进一步帮助您。
-
@Jonathon 已更新。
-
@mafortis,我使用你的代码。但我的
$category->route有错误。Undefined offset: 0。可以帮我吗?