sub category by php and mysql table - php

I have a table name category with following cols
cat_id | name | parent
1 | item 1 | 0
2 | item 2 | 1
3 | item 3 | 0
4 | item 4 | 1
5 | item 5 | 3
How i can display it in a menu like this
Item 1
> Item 2
> Item 4
Item 3
> Item 5
Please help

Here is the function that can be used:
// $current_cat_id: the current category id number
// $count: just a counter, call it as 0 in your function call and forget about it
// Gets the drop down list recurssively of categories //
function find_pages_recursive($current_cat_id, $count)
{
global $db; // the database object instance
static $option_results;
// if there is no current category id set, start off at the top level (zero)
if (!isset($current_cat_id))
{
$current_cat_id = 0;
}
$count++;
// query the database for the sub-categories of whatever the parent category is
$query = 'SELECT id, title from pages where parid = ' . $current_cat_id . ' order by id';
$get_options = $db->execute($query);
$num_options = $db->count_select();
// our category is apparently valid, so go ahead :P
if ($num_options > 0)
{
while (list($cat_id, $cat_name) = mysql_fetch_row($get_options))
{
// if its not a top-level category, indent it to show that its a child category
if ($current_cat_id != 0)
{
$indent_flag = '';
for ($x = 2; $x <= $count; $x++)
{
$indent_flag .= '----';
}
$indent_flag .= ' ';
}
$option_results[$cat_id] = $indent_flag . $cat_name;
// now call the function again, to recurse through the child categories
find_pages_recursive($cat_id, $count);
}
}
return $option_results;
}
How To Use It:
echo '<select name="pages" id="pages">' . "\n";
echo '<option value="">--Select Page--</option>' . "\n";
$get_options = find_pages_recursive(0, 0);
if (count($get_options) > 0)
{
foreach ($get_options as $key => $value)
{
$options .= "<option value=\"$key\"";
$options .= ">$value</option>\n";
}
}
echo $options;
echo '</select>' . "\n";
Make sure to connect to the database first :)

Related

How can I fetch results from a junction table and insert them as an array into a JSON object using PHP?

I have Articles with Categories in a mysql Database. I would like to print out all Articles with their corresponding Categories as JSON in PHP to fetch with my Vue-App.
I'm working with the following tables: Articles, Categories and Article_has_Category (junction table, many to many):
Articles
"ID" | "Title"
------------
1 | First
2 | Second
Categories
"ID" | "Category"
------------
1 | Lifestyle
2 | Webtech
Article_has_Categories
"ID" | "Article_ID" | "Category_ID"
--------------------------------------
1 | 1 | 1
2 | 1 | 2
The following PHP-Code selects and prints all Articles for my Frontend to fetch:
$stmt = $pdo->prepare("SELECT * FROM Articles;");
$stmt->bindParam(':param');
if ($stmt->execute()) {
$array = $stmt->fetchAll();
$jsonArray = json_encode($array);
print_r($jsonArray);
}
Printed JSON-Output:
[
{"ID":"1","Title":"First"},
{"ID":"2","Title":"Second"}
]
Is it somehow possible to insert all Categories as an array into that JSON-Output?
Desired JSON-Output:
[
{"ID":"1","Title":"First", "Categories": "[Lifestyle, Webtech]" },
{"ID":"2","Title":"Second", "Categories": "[]"}
]
Currently I'm building the desired object in my frontend first using "SELECT * FROM Articles;" to fetch all articles and then in a seperate call, fetching the corresponding categories by Article ID using the statement below:
SELECT c.Category
FROM article_has_category ac
INNER JOIN Categories c ON c.ID = ac.Category_ID
WHERE ac.Article_ID = :id;
Is there any solution combining the two statements and building the desired object directly in my PHP File?
Okay I solved this by assembling my own JSON in PHP, instead of using json_encode().
My code is not very pretty but I commented it a bit for you to understand:
<?php
$stmt = $pdo->prepare("
SELECT * FROM Articles;
");
$stmt_categories = $pdo->prepare("
SELECT c.Category
FROM article_has_category ac
INNER JOIN Categories c ON c.ID = ac.Category_ID
WHERE ac.Article_ID = :id;
");
if ($stmt->execute()) {
$result = $stmt -> fetchAll();
// count items in result, in order to determine later which is the last one
$numItems = count($result);
$i = 0;
// prepare the json-array to print out in the php file
$printArray = '[';
// for each article, run the second sql-statement using the article-ID
foreach( $result as $row ) {
$stmt_categories->bindParam(':id', $row['ID']);
// executing the second statement
if ($stmt_categories->execute()) {
$result_category = $stmt_categories -> fetchAll();
// save the fetched categories into a new array, using the function makeArray()
$categories = makeArray($result_category);
// build the json object by hand, no more need for json_encode()
$element = '{';
$element .= ' "ID": ';
$element .= '"' . $row['ID'] . '",';
$element .= $categories;
$element .= ' "Title": ';
$element .= '"' . $row['Title'] . '"';
$element .= '}';
if(++$i === $numItems) {
// if it's the last item, do nothing
} else {
// if not, add a comma
$element .= ',';
}
// add the built element to the printArray
$printArray .= $element;
}
}
$printArray .= ']';
// finally print the array
print_r($printArray);
}
function makeArray($categoryArray){
$category_element .= ' "Category": ';
$category_element .= "[";
$numCategories = count($categoryArray);
$n = 0;
foreach( $categoryArray as $row ) {
$category_element .= '"' . $row['Category'] . '"';
if(++$n === $numCategories) {
// if it's the last item, do nothing
} else {
// if not, add a comma
$category_element .= ',';
}
}
$category_element .= "],";
return $category_element;
}

Grouping MySQL output using data in one of the columns

Query result:
+--------+-----------+--------------+-----------+
| rol_id | pos_name | role_name | sys_name |
+--------+-----------+--------------+-----------+
| 2 | A Manager | Role A | System A |
| 1 | A Manager | Role B | System A |
| 105 | A Manager | Role A | System B |
| 106 | A Manager | Role B | System B |
| 107 | A Manager | Role C | System B |
| 108 | A Manager | Role D | System B |
| 4 | A Manager | Role A | System C |
| 25 | A Manager | Role A | System C |
| 100 | A Manager | Role A | System C |
Required output:
Position Name "A Manager" can access
"System A"
"Role A"
"Role B"
"System B"
"Role A"
"Role B"
"Role C"
"Role D"
etc.
Current code, using a for loop to grab the system names:
$posname = mysqli_fetch_array($posresult);
echo $posname['pos_name']. '<br/>';
echo 'A total of ' .$result->num_rows. ' rows were returned<br/>';
$numResults = $result->num_rows;
$all_results = array();
while ($row = mysqli_fetch_assoc($result)) {
// Append all rows to an array
$all_results[] = $row;
}
for($i = 0; $i < $numResults; $i++){
echo $all_results[$i]["sys_name"];
echo '<br/>';
}
I was intending to learn nested loops next, to put the roles under each system.
But the above lists each system for every row in the array (expected behaviour with the current code), how could I group the output so it looks as above, with each system listed once and each role associated with it printed beneath it?
EDIT
Thought I was making progress but now getting all roles under each system: -
$posname = mysqli_fetch_array($posresult);
echo $posname['pos_name']. '<br/>';
echo 'A total of ' .$result->num_rows. ' rows were returned<br/><br/>';
$numResults = $result->num_rows;
$all_results = array();
while ($row = mysqli_fetch_assoc($result)) {
// Append all rows to an array
$all_results[] = $row;
}
$j = 0;
while ($j < $numResults) {
$sysName = $all_results[$j]["sys_name"];
echo $sysName;
echo '<br/>';
for($i = 0; $i < $numResults; $i++){
if ($all_results[$i]["sys_name"] = $all_results[$j]["sys_name"]){
echo $all_results[$i]["role_name"];
echo '<br/>';
}
}
echo '<br/><hr/>';
$j++;
EDIT: var output. System is the same in each row, which is strange because it isn't if you run the query in MySQL?
array
(0 =>array
('rol_id' => '2','pos_name' => 'Manager A','role_name' => 'Role A','sys_name' => 'System A',),
1 =>array
('rol_id' => '1','pos_name' => 'Manager A','role_name' => 'Role B','sys_name' => 'System A',),
2 =>array
('rol_id' => '105','pos_name' => 'Manager A','role_name' => 'Role A','sys_name' => 'System A',),
3 =>array
('rol_id' => '106','pos_name' => 'Manager A','role_name' => 'Role B','sys_name' => 'System A',),
4 =>array
('rol_id' => '107','pos_name' => 'Manager A','role_name' => 'Role C','sys_name' => 'System A',),
EDIT 2: IF I grab var_export after setting the array, the systems are correct. The above is if I var_export after the loops at the bottom of the code
EDIT 3: So I was using = instead of == in my IF statement! I'm not quite there, but the output is looking a lot better. Will update when I work the last part out. Thanks for the comment below
EDIT FINAL: The below gives what I want, I now see what #ADyson was saying below about comparing the last row with the current. I've used $control for this. Had to play around with where to increment it, but it works now. Thanks all
$all_results = array();
while ($row = mysqli_fetch_assoc($result)) {
// Append all rows to an array
$all_results[] = $row;
}
//var_export($all_results);
$j = 0;
$control = $j;
//$all_results[$row['sys_name']][] = $row;
while ($j < $numResults) {
if ($control == $j){
echo 'System Name: ' . $all_results[$j]["sys_name"];
echo '<br/>';
for($i = 0; $i < $numResults; $i++){
if ($all_results[$i]["sys_name"] == $all_results[$j]["sys_name"]){
echo 'Role: ' . $all_results[$i]["role_name"];
echo '<br/>';
$control++;
}
}
echo '<br/>';
}
$j++;
}
$all_results = array();
while ($row = mysqli_fetch_assoc($result)) {
// Append all rows to an array
$all_results[] = $row;
}
//var_export($all_results);
$j = 0;
$control = $j;
//$all_results[$row['sys_name']][] = $row;
while ($j < $numResults) {
if ($control == $j){
echo 'System Name: ' . $all_results[$j]["sys_name"];
echo '<br/>';
for($i = 0; $i < $numResults; $i++){
if ($all_results[$i]["sys_name"] == $all_results[$j]["sys_name"]){
echo 'Role: ' . $all_results[$i]["role_name"];
echo '<br/>';
$control++;
}
}
echo '<br/>';
}
$j++;
}
Thanks to #ADyson, see first comment for the great guidance. The $control is how I implemented the suggestion

Optimizing / Simplify Query of Multi-Layer Category

I have a MySQL table ( name: item_categories ) having the following schema:
id INT(11) PRIMARY KEY, AUTO INCREMENT
category_name VARCHAR(100) NOT NULL
parent_id INT(11) NOT NULL, Default 0
Sample Data:
id category_name parent_id
=============================
1 Fruit 0
2 Animal 0
3 Furniture 0
4 Apple 1
5 Orange 1
6 Cat 2
7 Dog 2
8 Black Dog 7
9 White Dog 7
If I have to list out the categories with their parent categories, I have to loop through the database table many times.
My question is: How can I simplify the loop task?
Current loop task query:
// 1st query
$sql = "SELECT * FROM item_categories";
$rs = $db->query($sql);
while($row = $db->result($rs)) {
if((int)$row['parent_id'] === 0) {
// it is parent
echo $row['category_name'] . PHP_EOL;
} else {
$category = $row['category_name'];
// it has parent
$sql = "SELECT * FROM item_categories WHERE id=" . $row['parent_id'];
$rs2 = $db->query($sql);
$row2 = $db->result($rs);
$parent_id = (int)$row2['parent_id'];
while($parent_id != 0) {
$sql = "SELECT * FROM item_categories WHERE id=" . $row['parent_id'];
$rs2 = $db->query($sql);
$row2 = $db->result($rs);
$parent_id = (int)$row2['parent_id'];
$category = $row2['category_name'] . ' > ' . $category;
}
echo $category;
}
}
Which will output:
Fruit
Animal
Furniture
Fruit > Apple
Fruit > Orange
Animal > Cat
Animal > Dog
Animal > Dog > Black Dog
Animal > Dog > White Dog
Based on the link i gave you in the comment - try this:
function renderBreadcrumbs($db, $id, $path = null) {
$res = $db->query("SELECT id, parent_id, category_name FROM item_categories WHERE id = " . $id);
$row = $db->result($res);
$path = $row['category_name'] . ' > ' . $path;
if($row['parent_id'])
$path = renderBreadcrumbs($db, $row['parent_id'], $path);
return $path;
}
$res = $db->query("SELECT id, parent_id, category_name FROM item_categories ORDER BY parent_id ASC");
while($row = $db->result($res)) {
$breadcrumb = null;
if(!$row['parent_id'])
$breadcrumb .= $row['category_name'];
else
$breadcrumb .= renderBreadcrumbs($db, $row['parent_id'], $row['category_name']);
echo $breadcrumb . PHP_EOL;
}

Tree issue in PHP

i have a table General whose structure like this
----------------------------------
id | name | parent_id
------------------------------------
1 | root_category | Null
2 | Appare | 1
3 | Accessories | 1
4 | Shirt | 2
5 | Pants | 2
6 | hand Bags | 3
7 | jewelry | 3
And i store the value of general table using from in my product table
product table which contain all the information about product
in product table
p_id | 1
p_name | bla
p_weight | 250
g_id | 5
g_name | pants
g_parent | 2
i Want to generate complete tree using
->g_id -> g_name -> g_parent
tree should look like this
Root Category
- Apparel
-- Shirts
-- Pants
- Accessories
-- Handbags
-- Jewelry
i have tried recursive function but its not working which is
function get_categories($parent = $g_parent)
{
$html = '<ul>';
$query = mysql_query("SELECT * FROM `general` WHERE `parent_id` = '$parent'");
while($row = mysql_fetch_assoc($query))
{
$current_id = $row['id'];
$html .= '<li>' . $row['name'];
$has_sub = NULL;
$has_sub = mysql_num_rows(mysql_query("SELECT COUNT(`parent_id`) FROM `general` WHERE `parent_id` = '$current_id'"));
if($has_sub)
{
$html .= get_categories($current_id);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
print get_categories();
but its not working.... :(
You should try this... its working code.. also see the output screenshot (output screen)
<?php
function get_categories(){
$con = mysql_connect("localhost","root","");
if (!$con){
die('Could not connect: ' . mysql_error());
}
mysql_select_db("stackoverflow", $con);
$result = mysql_query("SELECT g.`name` AS `category`, GROUP_CONCAT(gj.`name`) AS `name`
FROM `general` g INNER JOIN `general` gj ON g.`id` = gj.`parent_id` GROUP BY g.`id` ");
$i=0;
while($row = mysql_fetch_array($result)){
$data[$i]['category'] = $row['category'];
$data[$i]['name'] = $row['name'];
$i++;
}
$html = $data[0]['category']."<br>";
unset($data[0]);
foreach($data as $key => $listing){
$html .= " - ".$listing['category']."<br>";
$exp = explode(",",$listing['name']);
$count_exp = count($exp);
for($j=0; $j<=$count_exp-1;$j++){
$html .= " -- ".$exp[$j]."<br>";
}
}
return $html;
}
print_r(get_categories());
?>
Output Screen
Change this
print get_categories();
To
print get_categories(1);
an empty string is not going to match a NULL value in MySQL, hence you need to supply your starting id. Unless you wanna modify your function to do the extra checking if $parent is null.
try this with some changing :
function get_categories($parent)
{
$html = '<ul>';
$query = mysql_query("SELECT * FROM `general` WHERE `parent_id` = '$parent'");
while($row = mysql_fetch_assoc($query))
{
$current_id = $row['id'];
$html .= '<li>' . $row['name'];
$has_sub = NULL;
$has_sub = mysql_num_rows(mysql_query("SELECT COUNT(`parent_id`) as count FROM `general` WHERE `parent_id` = '$current_id'")); // change here
if($has_sub['count'] > 0) // change here
{
$html .= get_categories($current_id);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
print get_categories(1); // change here

Nested dropdown

I'm building a form with php/mysql. I've got a table with a list of locations and sublocations. Each sublocation has a parent location. A column "parentid" references another locationid in the same table. I now want to load these values into a dropdown in the following manner:
--Location 1
----Sublocation 1
----Sublocation 2
----Sublocation 3
--Location 2
----Sublocation 4
----Sublocation 5
etc. etc.
Did anyone get an elegant solution for doing this?
NOTE: This is only psuedo-code.. I didn't try running it, though you should be able to adjust the concepts to what you need.
$parentsql = "SELECT parentid, parentname FROM table";
$result = mysql_query($parentsql);
print "<select>";
while($row = mysql_fetch_assoc($result)){
$childsql = "SELECT childID, childName from table where parentid=".$row["parentID"];
$result2 = mysql_query($childsql);
print "<optgroup label=\".$row["parentname"]."\">";
while($row2 = mysql_fetch_assoc($result)){
print "<option value=\"".$row["childID"]."\">".$row["childName"]."</option>\n";
}
print "</optgroup>";
}
print "</select>";
With BaileyP's valid criticism in mind, here's how to do it WITHOUT the overhead of calling multiple queries in every loop:
$sql = "SELECT childId, childName, parentId, parentName FROM child LEFT JOIN parent ON child.parentId = parent.parentId ORDER BY parentID, childName";
$result = mysql_query($sql);
$currentParent = "";
print "<select>";
while($row = mysql_fetch_assoc($result)){
if($currentParent != $row["parentID"]){
if($currentParent != ""){
print "</optgroup>";
}
print "<optgroup label=\".$row["parentName"]."\">";
$currentParent = $row["parentName"];
}
print "<option value=\"".$row["childID"]."\">".$row["childName"]."</option>\n";
}
print "</optgroup>"
print "</select>";
Are you looking for something like the OPTGROUP tag?
optgroup is definitely the way to go. It's actually what it's for,
For example usage, view source of http://www.grandhall.eu/tips/submit/ - the selector under "Grandhall Grill Used".
You can use and space/dash indentation in the actual HTML. You'll need a recusrive loop to build it though. Something like:
<?php
$data = array(
'Location 1' => array(
'Sublocation1',
'Sublocation2',
'Sublocation3' => array(
'SubSublocation1',
),
'Location2'
);
$output = '<select name="location">' . PHP_EOL;
function build_items($input, $output)
{
if(is_array($input))
{
$output .= '<optgroup>' . $key . '</optgroup>' . PHP_EOL;
foreach($input as $key => $value)
{
$output = build_items($value, $output);
}
}
else
{
$output .= '<option>' . $value . '</option>' . PHP_EOL;
}
return $output;
}
$output = build_items($data, $output);
$output .= '</select>' . PHP_EOL;
?>
Or something similar ;)
Ideally, you'd select all this data in the proper order right out of the database, then just loop over that for output. Here's my take on what you're asking for
<?php
/*
Assuming data that looks like this
locations
+----+-----------+-------+
| id | parent_id | descr |
+----+-----------+-------+
| 1 | null | Foo |
| 2 | null | Bar |
| 3 | 1 | Doe |
| 4 | 2 | Rae |
| 5 | 1 | Mi |
| 6 | 2 | Fa |
+----+-----------+-------+
*/
$result = mysql_query( "SELECT id, parent_id, descr FROM locations order by coalesce(id, parent_id), descr" );
echo "<select>";
while ( $row = mysql_fetch_object( $result ) )
{
$optionName = htmlspecialchars( ( is_null( $row->parent_id ) ) ? "--{$row->descr}" : "----{$row->desc}r", ENT_COMPAT, 'UTF-8' );
echo "<option value=\"{$row->id}\">$optionName</option>";
}
echo "</select>";
If you don't like the use of the coalesce() function, you can add a "display_order" column to this table that you can manually set, and then use for the ORDER BY.

Categories