В моем приложении 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
Есть идеи?
UPDATE
Хорошо, я решил это :-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 = [])
{
идеи?