我的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
在Blade中创建太多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'));
}
有什么主意吗?
基于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 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 = [])
{
想法?
答案 0 :(得分:0)
这是可能的,但是您必须注意脚本的性能,因为它最终可能会完成许多数据库查询以确定每个类别路由。
我的建议是创建一个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
请注意,可能还有其他解决方案。我只是在没有太多思考的情况下碰到了这个。另外,上面的代码尚未经过测试,因此请注意,可能需要进行一些小的更改才能使其正常工作。