Граф вложенных детей Laravel (Категории) - PullRequest
0 голосов
/ 07 ноября 2018

Я использовал вложенные категории на своем сайте Laravel со стилем таблиц mysql в стиле списка смежности. Существует максимум 7 уровней категоризации (при использовании таксономия категорий Google ). Пожалуйста, см. Изображение ниже для небольшого образца данных и код ниже для отношений моей модели категории.

Каждая категория имеет от нуля до многих подкатегорий (используя одну и ту же модель категории), а также от нуля до многих страниц под ней. Моя цель здесь - найти способ подсчета всех страниц в категории (включая страницы в ее подкатегориях).

MySql Table Layout Example

Модель моей категории имеет следующие взаимосвязи, которые все функционируют:

public function pages() {
    return $this->hasMany('App\Models\Page');
}

public function children() {
    return $this->hasMany('App\Models\Category', 'parent_id' );
}

public function parent() {
    return $this->belongsTo('App\Models\Category', 'parent_id' );
}

public function childrenRecursive() {
   return $this->children()->orderBy( 'name' )->with('childrenRecursive', 'pages');
}

public function parentRecursive() {
   return $this->parent()->with('parentRecursive');
}

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Поскольку я с нетерпением жду загрузки всех этих категорий и страниц на первом месте, используя следующую строку кода и мою модель категорий:

$categories = Category::with( 'childrenRecursive' )->whereNull( 'parent_id' )->get();

Мне удалось использовать рекурсивную формулу для суммирования количества страниц под каждой категорией без замедления страницы:

foreach( $categories as $category ) {
    $category->pagesCount = 0;
    $category->pagesCount += $category->pages->count();
    foreach( $category->childrenRecursive as $child ) {
        $category->pagesCount += countChildPages( $child );
    }
}

function countChildPages( $category ) {
    $category->pagesCount = 0;
    $category->pagesCount += $category->pages->count();
    foreach( $category->childrenRecursive as $child ) {
        $category->pagesCount += countChildPages( $child );
    }
    return $category->pagesCount;
}

Затем я просто обращался к счетчику ($ category-> pagesCount) всякий раз, когда мне нужно было использовать его на странице.




Пример страницы sitemap.html:

foreach( $categories as $category ) {
    $category->pagesCount = 0;
    $category->pagesCount += $category->pages->count();
    foreach( $category->childrenRecursive as $child ) {
        $category->pagesCount += countChildPages( $child );
    }
}

foreach( $categories as $category ) {
    if( $category->pagesCount > 0 ) {
        echo '<div class="category">';
            echo '<h2><a href="https://example.com/' . $category->slug . '">' . $category->name . ' (' . $category->pagesCount . ')</a></h2>';
            foreach( $category->pages as $page ) {
                showPage( $page );
            }
            foreach( $category->childrenRecursive as $child ) {
                showSubCategory( $child );
            }
        echo '</div>';
    }
}

function countChildPages( $category ) {
    $category->pagesCount = 0;
    $category->pagesCount += $category->pages->count();
    foreach( $category->childrenRecursive as $child ) {
        $category->pagesCount += countChildPages( $child );
    }
    return $category->pagesCount;
}

function showSubCategory( $category ) {
    if( $category->pagesCount > 0 ) {
        echo '<div class="category">';
            echo '<h2><a href="https://example.com/' . $category->slug . '">' . $category->name . ' (' . $category->pagesCount . ')</a></h2>';
            foreach( $category->pages as $page ) {
                showPage( $page );
            }
            foreach( $category->childrenRecursive as $child ) {
                showSubCategory( $child );
            }
        echo '</div>';
    }
}

function showPage( $page ) {
    echo '<div class="category page">';
        echo '<h2><a href="https://example.com/' . $page->slug . '">' . $page->title . '</a></h2>';
    echo '</div>';
}
0 голосов
/ 08 ноября 2018

Это не то, как я бы делал это, используя отношения, но хитрый способ был бы:

public function childCount(){
  return DB::table('categories')->where('slug', 'LIKE', $this->slug . '%')->count() - 1;
}

Чтобы получить страницы, возможно:

public function pageCount(){
  return Page::whereIn('category_id', 
     DB::table('categories')->select('id')->where('slug', 'LIKE', $this->slug . '%')->get()->pluck('id')
  )->count();
}

2 запроса, которые, возможно, можно было бы оптимизировать, но которые будут работать

...