I have 2 tables posts
and categories
, There is one-to-many
relation between both tables.
Here are the two tables:
posts table _________________________________________________________________ | id | title | content | category_id | post_order | post_active | |____|_______|_________|_____________|_____________|_____________| | 1 | test1 | testing | 1 | 0 | 1 | | 2 | test2 | testing | 1 | 1 | 1 | | 3 | test3 | testing | 2 | 2 | 0 | | . | ..... | ....... | . | . | . | |____|_______|_________|_____________|_____________|_____________| categories table _____________________________________ | c_id | c_name | c_order | c_active | |______|________|_________|__________| | 1 | cat1 | 0 | 1 | | 2 | cat2 | 1 | 1 | | 3 | cat3 | 2 | 0 | | . | ..... | ....... | . | |______|________|_________|__________|
There is a relation between category_id
and c_id
, So that the category_id
in the posts
table refers to the category id c_id
.
The post_order
and c_order
are used to order both posts
and categories
.
And the post_active
and c_active
are used to define if it would be displayed for the users or not, 1
means yes it will be displayed, While 0
is no.
I show the categories
and the posts
are beneath them like:
________________________________________ | | | | | cat1 | cat2 | cat3 | | (active) |__________|__________| | | | | | test1 | | testing | | | | test2 | | testing | |_______________________________________|
The code to display the data:
//That query should get the active categories and posts ordered by the order column, Not sure if it's correct. $results = $conn->prepare("SELECT * FROM categories LEFT JOIN categories ON categories.c_id = posts.id WHERE categories.c_active = '1' and posts.post_active = '1' order by categories.c_order, posts.post_order ASC"); //Execute the previous query. $results->execute(); while ($row = $results->fetch(PDO::FETCH_ASSOC)) { $categories[$row['category_name']][] = $row; } //Print the categories foreach (array_keys($categories) as $category_name) { echo $category_name; } //Print the posts foreach ($categories as $category_name => $posts) { foreach ($posts as $post) { echo $post['title']; } }
There is HTML code inside the previous PHP code for creating tabs and accordion for each post, If that would help, Here is the full code:
<!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <?php foreach (array_keys($categories) as $category_name) { ?> <li role="presentation"><a href="#<?php echo str_replace(' ', '', $category_name); ?>" aria-controls="<?php echo str_replace(' ', '', $category_name); ?>" role="tab" data-toggle="tab"><?php echo $category_name; ?></a></li> <?php } ?> </ul> <!-- .nav-tabs --> <!-- Tab panes --> <div class="tab-content"> <?php foreach ($categories as $category_name => $posts) { ?> <div role="tabpanel" class="tab-pane fade" id="<?php echo str_replace(' ', '', $category_name); ?>"> <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> <?php foreach ($posts as $post) { ?> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingOne"> <h4 class="panel-title"> <a role="button" class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#<?php echo $post['id']; ?>_faq" aria-expanded="false" aria-controls="#<?php echo $post['id']; ?>_faq"> <?php echo $post['title'] ?> </a> </h4> </div> <div id="<?php echo $post['id']; ?>_faq" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <?php echo $post['content']; ?> </div> <!-- .panel-body --> </div> <!-- .panel-collapse --> </div> <!-- .panel-default --> <?php } ?> </div> <!-- .panel-group --> </div> <!-- .tab-pane --> <?php } ?> </div> <!-- .tab-content -->
I should get all the active categories
and posts
, But I only get the first active category with its posts ordered.
Advertisement
Answer
I’ll recommend this query:
SELECT b.c_name, a.id, TRIM(a.title) AS title, a.content FROM posts a INNER JOIN categories b ON a.category_id = b.c_id WHERE a.post_active = '1' AND b.c_active = '1' ORDER BY b.c_order, a.post_order
- Rather than asking php to trim the title, just fix it up within the query.
- I am using
INNER JOIN
because I expect all rows inposts
will have a corresponding row incategories
. - Order by
c_order
thenpost_order
so that categorical entries are grouped together when you iterate the resultset.
Based on my demo: http://sqlfiddle.com/#!9/4ca1a1/3
And referencing fetchAll
‘s FETCH_GROUP…
$resultset = fetchAll(PDO::FETCH_GROUP); /* should generate: $resultset = [ "social" => [ ["id" => 5, "title" => "fifth title", "content" => "fifth content"], ["id" => 4, "title" => "fourth title", "content" => "fourth content"], ["id" => 2, "title" => "second title", "content" => "second content"] ], "tech" => [ ["id" => 1, "title" => "first title", "first content"] ] ]; */
Your categories are in array_keys($resultset)
.
And you can iterate the prepared resultset and access the first level keys and the subarray rows to display the data.