简体   繁体   English

如何获取类别、文章和子类别及其文章?

[英]How to fetch categories, articles and subcategories and their articles?

I want to output the category names, the subcategory names in each category, and the articles in each category and in each subcategory.我想输出类别名称,每个类别中的子类别名称,以及每个类别和每个子类别中的文章。

The output should be in <ul> and inner <ul> tags in HTML.输出应该在 HTML 中的<ul>和内部<ul>标签中。

Here is how the output should look like:下面是输出的样子:

HTML 输出

I have these 5 tables:我有这 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, ...)

I have made this SQL so far:到目前为止,我已经制作了这个 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

When I look at your desired output, what I see is a tree with leaves that may or may not link to an article.当我查看您想要的输出时,我看到的是一棵树,叶子可能会或可能不会链接到文章。 A leaf that doesn't have an article attached to it can be thought of as a category.没有附加文章的叶子可以被认为是一个类别。 A leaf that does have an article can be thought of as an article.有文章的叶子可以被认为是文章。

With this assumption, you can build your schema:有了这个假设,您可以构建您的架构:

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

(Granted, this isn't in 4th normal form. you can normalize if needed, but for now it would be premature optimization) (当然,这不是第四范式。如果需要,您可以标准化,但现在这将是过早的优化)

Now, it should be easier to see how to tackle your problem: all you have to do is first build the tree in a php array;现在,应该更容易了解如何解决您的问题:您所要做的就是首先在 php 数组中构建树; then iterate through that array and individually query the details for each leaf (or at least for what you need for your link's href and text).然后遍历该数组并单独查询每个叶子的详细信息(或至少查询链接的 href 和文本所需的内容)。

A simple recursion primer:一个简单的递归入门:

<?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);

*Caveat: this doesn't translate directly to unordered lists. *警告:这不会直接转换为无序列表。 I dislike mixing html and logic, but in this case you would need to build a string inside the recursion.我不喜欢混合 html 和逻辑,但在这种情况下,您需要在递归中构建一个字符串。 This is a more focused question you could ask or research.这是您可以提出或研究的更集中的问题。

Now, you iterate through $idList and look up the needed information to fill in your desired title现在,您遍历$idList并查找所需的信息以填写您想要的标题

psuedocode (db retrieval again left to the reader):伪代码(数据库检索再次留给读者):

// $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;  
}

Then, when you're outputting your html, you just iterate through $idList again and put in the values as needed.然后,当您输出 html 时,您只需再次遍历$idList并根据需要输入值。

Obviously, this isn't a cut and paste answer;显然,这不是一个剪切和粘贴的答案; there's way too much coding to do.有太多的编码要做。 But hopefully this points you into a workable direction.但希望这会为您指明一个可行的方向。

Instead of doing it in a single query, I would suggest a solution of looping over separate, multiple queries.我建议不要在单个查询中执行此操作,而是建议使用循环处理单独的多个查询的解决方案。

For your case, only 3 separate queries are needed because you have 3-tier (Cat/Subcat/Article).对于您的情况,只需要 3 个单独的查询,因为您有 3 层(Cat/Subcat/Article)。 On the other hand, since the number of tiers is already defined (and limited), there is no need to use recursion this time (if there are unlimited (or unknown) levels of hierarchy, we may need recursion).另一方面,由于层的数量已经定义(并且是有限的),所以这次不需要使用递归(如果有无限(或未知)的层次结构,我们可能需要递归)。

Please change the database schema to a proper, and clearly defined one (as follows):请将数据库架构更改为适当且明确定义的架构(如下):

category (catid, name)
subcategory (subcatid, catid, name)
article (articleid, catid, subcatid, name)

where catid is linking to category ; catid is linking to category and subcatid is linking to subcategory , if applicable并且subcatid is linking to subcategory如果适用

So the data will be (refering to the picture in your post)所以数据将是(参考你帖子中的图片)

category (catid, name)

1 Category1
2 Category2
3 Category3

subcategory (subcatid, catid, name)

1 2 Subcategory1

article (articleid, catid, subcatid, name)

1 0 0 Article6
2 1 0 Article1
3 2 1 Article7
4 2 1 Article8
5 2 0 Article2
6 2 0 Article3
7 3 0 Article4
8 3 0 Article5

I think the advantage and clarity is obvious in the above schema, so I don't think further explanation is needed.我认为上述模式的优势和清晰度是显而易见的,因此我认为不需要进一步解释。 Of course you may add further data fields to the tables but the main structure is as above.当然,您可以向表中添加更多数据字段,但主要结构如上。

Now, please use PHP to generate the following HTML:现在,请使用 PHP 生成以下 HTML:

For 1st ul, li (just run once)对于第一个 ul, li(只运行一次)

(a) loop over category and display the name (a) 遍历类别并显示名称

then然后

(b) loop over article display records having (catid=0 or catid is null) and (subcatid=0 or subcatid is null) , then display the name (b) 循环具有 (catid=0 or catid is null) 和 (subcatid=0 or subcatid is null) 的文章显示记录,然后显示名称

2nd ul,li第二个 ul,li

For each of the records in (a) above:对于上述 (a) 中的每条记录:

(c) loop over subcategory which as catid=category.catid and display the subcategory name (c) 遍历子类别,其中 catid=category.catid 并显示子类别名称

then然后

(d) loop over article, display records having catid=category.catid and (subcatid=0 or subcatid is null) , then display the name (d) 遍历文章,显示具有 catid=category.catid 和 (subcatid=0 or subcatid is null) 的记录,然后显示名称

3rd ul,li第三个 ul,li

For each of the records in (c) above:对于上述 (c) 中的每条记录:

(e) loop over article, display records having catid=subcategory.catid and subcatid=subcategory.subcatid , then display the name (e) 遍历文章,显示具有 catid=subcategory.catid 和 subcatid=subcategory.subcatid 的记录,然后显示名称

To demonstrate, I will put the "2nd ul, li" as a function known as branch2() ;为了演示,我将把“2nd ul, li”作为一个名为branch2()的函数; and "3rd ul, li" as a function known as branch3() , and then call them accordingly.和“3rd ul, li”作为称为branch3()的函数,然后相应地调用它们。

So, the code will be:所以,代码将是:

<?php

$servername = "localhost";
$username = "xxxxxxx";
$password = "xxxxxxxxxx";
$dbname = "xxxxxx";

// Create connection

$conn = new mysqli($servername, $username, $password, $dbname);


$sql1="(
SELECT name, catid AS id1, '1' as subdata
FROM category
ORDER BY id1
)
UNION (

SELECT name, articleid AS id1, '0' as subdata
FROM article
WHERE catid =0
AND subcatid =0
ORDER BY id1
)";

$result = $conn -> query($sql1);

$index=0;

$count=mysqli_num_rows($result);

echo "<ul>";
  while ($index <$count) {
  $row = $result -> fetch_assoc() ;
  echo "<li>". $row["name"];

if ($row["subdata"]=='1'){  
    branch2($row["id1"], $conn); 
}
  
  $index++;
  }
echo "</ul>";

$result -> free_result();


function branch2($var1, $conn)
{

$sql2="(
SELECT name, catid AS id1, subcatid as id2, 1 as subdata
FROM subcategory where catid=". $var1 . " ORDER BY id1 )
UNION (
SELECT name, articleid AS id1, 0 as id2 , 0 as subdata
FROM article
WHERE catid =" . $var1 . " AND subcatid =0 ORDER BY id1 )";


$result2 = $conn -> query($sql2);

$index2=0;

$count2=mysqli_num_rows($result2);

echo "<ul>";
  while ($index2 <$count2) {
  $row2 = $result2 -> fetch_assoc() ;
  echo "<li>". $row2["name"];

if ($row2["subdata"]=='1') {    
    branch3($row2["id1"], $row2["id2"], $conn); 
}  
   $index2++;
  }
echo "</ul>";
$result2 -> free_result();
}


function branch3($var1, $var2, $conn)
{

$sql3="(
SELECT name, articleid AS id1, 0 as id2 , 0 as subdata
FROM article
WHERE catid =" . $var1 . " and subcatid=". $var2 . " ORDER BY id1 )";

$result3 = $conn -> query($sql3);

$index3=0;

$count3=mysqli_num_rows($result3);

echo "<ul>";
  while ($index3 <$count3) {
  $row3 = $result3 -> fetch_assoc() ;
  echo "<li>". $row3["name"];

  $index3++;
  }
echo "</ul>";

$result3 -> free_result();

}

?>

The fully working example can be seen here:完整的工作示例可以在这里看到:

http://www.createchhk.com/SO/testso10Nov2021.php http://www.createchhk.com/SO/testso10Nov2021.php

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM