首页 > 解决方案 > 如何获取类别、文章和子类别及其文章?

问题描述

我想输出类别名称,每个类别中的子类别名称,以及每个类别和每个子类别中的文章。

输出应该是 HTML 中的 in<ul>和 inner<ul>标记。

以下是输出的样子:

HTML 输出

我有这 5 张桌子:

table_article_categories(articlecat_id, parent_id, articlecat_status, ...)
table_article_to_article_categories(articlecat_id, articles_id)
table_articles(articles_id, articles_status, ...)
table_articles_description(articles_id, language_id, articles_heading_title, ...)
table_article_categories_description(articlecat_id, articlecat_name, language_id, ...)

到目前为止,我已经制作了这个 SQL:

  SELECT
        ac.parent_id,
        ac.articlecat_id,
        a.articles_id,
        ad.articles_heading_title AS article_name,
        acd.articlecat_name
  FROM
        table_article_categories AS ac
  LEFT JOIN
        table_article_to_article_categories AS atac
     ON
        atac.articlecat_id = ac.articlecat_id
  LEFT JOIN
        table_articles AS a
     ON
        a.articles_id = atac.articles_id
     AND                
        a.articles_status = 1
  LEFT JOIN
        table_articles_description AS ad
     ON
        ad.articles_id = a.articles_id
     AND
        ad.language_id = 1              
  INNER JOIN
        table_article_categories_description AS acd
     ON
        acd.articlecat_id = ac.articlecat_id
     AND
        acd.language_id = 1
  WHERE
        ac.parent_id = 99 # --- This is the root article-categori-id ---
     AND
        ac.articlecat_status = 1
     AND
        ac.articlecat_id != 77 # --- This is an excluded article-categori-id ---
  ORDER BY
        acd.articlecat_name ASC,
        article_name ASC

标签: phpmysqlsqlrecursiontree-structure

解决方案


当我查看您想要的输出时,我看到的是一棵带有叶子的树,它可能链接到一篇文章,也可能不链接到一篇文章。没有附加文章的叶子可以被认为是一个类别。有文章的叶子可以被认为是文章。

有了这个假设,您可以构建您的架构:

Category_Tree  Category      Article
------------   --------      -------
id             id            id
pid            category_id   article_id
article_id     language_id   language_id
category_id    title         title

(当然,这不是第 4 范式。如果需要,您可以进行归一化,但现在这将是过早的优化)

现在,应该更容易看到如何解决您的问题:您所要做的就是首先在 php 数组中构建树;然后遍历该数组并单独查询每个叶子的详细信息(或至少查询链接的 href 和文本所需的内容)。

一个简单的递归入门:

<?php
/*
 Category_Tree
 id  pid  name            article_id   category_id   
 1   0    Category 1            ...          ...
 2   1    Article 1
 3   0    Category 2
 4   3    SubCategory 1
 5   4    Article 7
 6   4    Article 8
 7   3    Article 2
 8   3    Article 3
 9   0    Category 3
 10  9    Article 4
 11  9    Article 5
 12  0    Article 6
*/
function getRecord($pid) : array
{
  // database access is left to the reader

  // $db->run('SELECT * FROM CATEGORY_TREE WHERE PID=?',[$pid]);
  // $rows = [];
  // while($row = $db->getRow()) {
  //     $rows[] = $row;
  // }

  return $rows;
}

function makeTree($pid) : array
{
    static $idList = [];
    static $indent = 0;
    $rows = getRecord($pid);
    foreach ($rows as $row) {
        $idList[] = [
            'id' => $row->id, 
            'indent' => $indent,
            'articleId' => $row->articleId,
            'categoryId' => $row->categoryId,
        ];
        $indent++;
        makeTree($row->id);
        $indent--;
    }

    return $idList;
}

$idList = makeTree(0);

*警告:这不会直接转化为无序列表。我不喜欢混合 html 和逻辑,但在这种情况下,您需要在递归中构建一个字符串。这是您可以提出或研究的更集中的问题。

现在,您遍历$idList并查找所需的信息以填写您想要的标题

伪代码(数据库检索再次留给读者):

// $languageId is already assigned as you see fit

// add title to $idList
foreach($idList as $index => $row) {
    if($row->articleId ?? FALSE) {
      $db->run('SELECT TITLE FROM ARTICLE WHERE ARTICLE_ID=? AND LANGUAGE_ID=?', [$row->articleId, $languageID]);
    } else {
      $db->run('SELECT TITLE FROM CATEGORY WHERE CATEGORY_ID=? AND LANGUAGE_ID=?', [$row->categoryId, $languageId]);
    }

    $row->title = $db->get('title');
    $idList[$index] = $row;  
}

然后,当您输出 html 时,您只需$idList再次遍历并根据需要输入值。

显然,这不是一个剪切和粘贴的答案。有太多的编码要做。但希望这能为您指明一个可行的方向。


推荐阅读