PHP MySQL building a 3 Tier multi dimensional array - php

So I have my query, its returning results as expect all is swell, except today my designer through in a wrench. Which seems to be throwing me off my game a bit, maybe its cause Im to tired who knows, anyway..
I am to create a 3 tier array
primary category, sub category (which can have multiples per primary), and the item list per sub category which could be 1 to 100 items.
I've tried foreach, while, for loops. All typically starting with $final = array(); then the loop below that.
trying to build arrays like:
$final[$row['primary]][$row['sub']][] = $row['item]
$final[$row['primary]][$row['sub']] = $row['item]
I've tried defining them each as there own array to use array_push() on. And various other tactics and I am failing horribly. I need a fresh minded person to help me out here. From what type of loop would best suit my need to how I can construct my array(s) to build out according to plan.
The Desired outcome would be
array(
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
)

Something like this during treatment of your request :
if (!array_key_exists($row['primary'], $final)) {
$final[$row['primary']] = array();
}
if (!array_key_exists($row['sub'], $final[$row['primary']])) {
$final[$row['primary']][$row['sub']] = array();
}
$final[$row['primary']][$row['sub']][] = $row['item'];

Something like this....
$final =
array(
'Primary1'=>array(
'Sub1'=>array("Item1", "Item2"),
'Sub2'=>array("Item3", "Item4")
),
'Primary2'=>array(
'Sub3'=>array("Item5", "Item6"),
'Sub4'=>array("Item7", "Item8")
),
);
You can do it using array_push but it's not that easy since you really want an associative array and array_push doesn't work well with keys. You could certainly use it to add items to your sub-elements
array_push($final['Primary1']['Sub1'], "Some New Item");

If I understand you correctly, you want to fetch a couple of db relations into an PHP Array.
This is some example code how you can resolve that:
<?php
$output = array();
$i = 0;
// DB Query
while($categories) { // $categories is an db result
$output[$i] = $categories;
$ii = 0;
// DB Query
while($subcategories) { // $subcategories is an db result
$output[$i]['subcategories'][$ii] = $subcategories;
$iii = 0;
// DB Query
while($items) { // $items is an db result
$output[$i]['subcategories'][$ii]['items'][$iii] = $items;
$iii++;
}
$ii++;
}
$i++;
}
print_r($output);
?>

Related

Paginate Tree Array

I am looking at trying to build pagination method for an array. I have an array something like below. Before you suggest making the pagination work for sql query, I have already done so and it did work for a flat array but a requirement is having this multidimensional tree array.
array = (
item_id = 5,
parent_id = 0,
children = array(
array(
item_id = 20,
parent_id = 5,
children = array(
array(
item_id = 24,
parent_id = 20
),
array(
item_id = 24,
parent_id = 20
)
)
)
)
);
What methods that I can find don't seem to work with such an array since array_slice will only work on the first level of the array and doesn't take into consideration the children levels.
/*
$root =
[
'id' => 1,
'children' => [...]
]
$queue[] = $root
$visiteds[] = $root
while ($queue){
$current = array_shift($queue);
// do whatever with the current ex: echo $current."<br>"
if $current has children {
foreach child {
if ($child NOT in $visiteds) { // $child not visited before
$visiteds[] = $child // mark as visited
$queue[] = $child // add to queue
// do whatever with the child ex: echo $child ."<br>"
}
}
}
}
*/
Note: if you want to visit exactly same children as required (for example 2 exactly same child must be visited twice then, remove $visiteds related parts. In this case be careful that your graph structure must not have cycling.)
You may consider to read about Graph Theory, Breadth First Search algorithm, Depth First Search algorithm.

post an array and iterate throught it in PHP codeigniter

This is the first time i create my own webservice (someone always did it for me before), so please bear with me.
I post this array :
$data = array(
'user_id' => $this->post('user_id'),
'group_id' => $this->post('group_id'),
'child_id' => $this->post('child_id'), //will be nested array
'custom' => $this->post('custom'),
'time' => $this->post('time'),
'date' => $this->post('date')
);
I tried to create a nested array with this : $this->post('child_id'), because user can post multiple child_id at once.
Then i tried to iterate through the child_id, because i need to insert them to the mysql :
for($i = 0; $i < sizeof($data['child_id']); $i++)
{
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data, $result_id[0]['id']);
}
What should i do, so i can have an array of child_id in my $data array? (nested array)
And how to iterate through it?
UPDATE :
I have updated the codes above.
I use advanced rest client for testing, and i tried to post something like this in the form content type :
child_id=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id=2
Notice that theres two child_id (left most and right most), but only the last one (right most) is inserted.
And this is the add_trans in the model :
function add_trans($table, $data, $schedule_id) {
$query = $this->db->insert($table, array('child_id' => $data['child_id'], 'schedule_id' => $schedule_id));
return $query;
}
Thanks a lot for your time.
Even thought you set the name attribute as child[] on the markup,
You still need to call it as:
'child_id' => $this->post('child_id')
It will still return an array.
for($i = 0; $i < sizeof($data['child_id']); $i++) {
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data, $result_id[0]['id']);
}
EDIT:
Looking upon you query string, that seems to be the culprit:
child_id=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id=2
^ same index , same index, same index, it will overwrite and you will get only `2`
If you want to get them all into an array format, you need to set them like this
child_id[]=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id[]=2
^ it needs to be set like this
UPDATE:
And in your model, if you want each id per row, well you can also loop in this case:
function add_trans($table, $data, $schedule_id) {
foreach($data['child_id'] as $child_id) {
$query = $this->db->insert($table, array('child_id' => $child_id, 'schedule_id' => $schedule_id));
}
// return $this->db->insert_id();
return $query;
}
ofcourse that won't work, it has to be
for($i = 0; $i < sizeof($data['child_id']); $i++)
{
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data['child_id'][$i], $result_id[0]['id']);
}
because you've not set $data['child_id[]'] so it doesn't exist, the key is just a string or number, it does not validate or parse anything
you don't need to give child[] in post method. just give only child, it will get complete array what are you sending from views
replace
'child_id' => $this->post('child_id[]')
with
'child_id' => $this->post('child_id')

Associative array's loaded from database and display as 'columns'

I am trying to create an overview of product properties, for an invoice system.
So far, most things are comming together using classes and PDO.
I have the following issue.
In my class, i've created a function that builds my products array.
It loads some information from the database, to build this array.
This array, i want to use to display all the products i have selected:
$prod1 - $prod1Name - $prod1Descr - $prod1Price
$prod2 - $prod2name - $prod2Descr - $prod2Price
etc.
I figured that the Associative array would help me creating columns.
Though the problem is, that i do not understand a bit how to create multiple lines and columns this way.
I was thinking of something like:
$prod[1]["name"] - $prod[1]["descr"] - etc
Then to use this in a foreach loop to create as many new lines as required.
The only thing i could come up with is on my index.php (as shown below), cause using an index (the [1] defenition) does not seem to work the way i think it should be implemented.
For my understanding, i assigend the var in my class as an array, then redefine an array when loading the database information.
Could anyone tell me how i could try to solve this issue?
I have the following class:
<?
class Invoice{
var $vendorID;
var $product = array();
function product_array(){
global $db;
$query = $db->conn->prepare('
SELECT ProductName, ProductDescription, ProductDuration, ProductPriceInclVat, ProductPriceExclVat, ProductVatType
FROM products WHERE VendorID = :VendorID
');
$array = array (
'VendorID' => $this->vendorID
);
$query->execute($array);
$result = $query->fetchall();
if (empty($result)){
echo"Could not find any products matching your criteria.";
die;
} else {
foreach($result as $row) {
$this->product = array("Name" => $row['ProductName'],
"Description" => $row['ProductDescription'],
"Duration" => $row['ProductDuration'],
"PriceExclVat" => $row['ProductPriceExclVat'],
"PriceInclVat" => $row['ProductPriceInclVat'],
"VatType" => $row['ProductVatType']
);
}
}
}
}
?>
and then i have the following code on my index.php:
<?
$invoice = new Invoice();
foreach ($invoice->product as $key => $value){
echo $key . "<br>";
echo $value . "$value";
echo "<br>";
}
?>
When you are assigning the result arrays to the product property you are overwriting the array every time. You need to append to the array instead, so something like:
$this->product = array();
foreach($result as $row) {
$this->product[] = array(...);
}
Alternatively, you could just assign the results of fetchAll to the product property if you don't need to rename the field keys (or you could alias them in the SQL).
$query = $db->conn->prepare('
SELECT ProductName as Name,
ProductDescription as Description,
ProductDuration as Duration,
ProductPriceInclVat as PriceInclVat,
ProductPriceExclVat as PriceExclVat,
ProductVatType as VatType
FROM products WHERE VendorID = :VendorID
');
$array = array (
'VendorID' => $this->vendorID
);
$query->execute($array);
$product = $query->fetchall(PDO::FETCH_ASSOC);
The $product is now in the format you require.
After this you can avoid foreach loop in class invoice.
Other thing i noticed that you have made function product_array() which is not called,
so in index.php you are getting empty array (defined in class Invoice).
So in Invoice class it should be
$product = product_array()
and product_array function should return the value.

Array key exists in multidimensional array

I'm trying to arrange a group of pages in to an array and place them depending on their parent id number. If the parent id is 0 I would like it to be placed in the array as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->parent_id] = array();
}
}
But if the parent id is set I'd like to place it in to the relevant array, again as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->id] = array();
} else if($obj->parent_id) {
$sorted[$obj->parent_id][$obj->id] = array();
}
}
This is where I begin to have a problem. If I have a 3rd element that needs to be inserted to the 2nd dimension of an array, or even a 4th element that needs inserting in the 3rd dimension I have no way of checking if that array key exists. So what I can't figure out is how to detect if an array key exists after the 1st dimension and if it does where it is so I can place the new element.
Here is an example of my Database Table
id page_name parent_id
1 Products 0
2 Chairs 1
3 Tables 1
4 Green Chairs 2
5 Large Green Chair 4
6 About Us 0
Here is an example of the output I'd like to get, if there is a better way to do this I'm open for suggestions.
Array([1]=>Array([2] => Array([4] => Array([5] => Array())), [3] => Array()), 6 => Array())
Thanks in advanced!
Well, essentially you are building a tree so one of the ways to go is with recursion:
// This function takes an array for a certain level and inserts all of the
// child nodes into it (then going to build each child node as a parent for
// its respective children):
function addChildren( &$get_pages, &$parentArr, $parentId = 0 )
{
foreach ( $get_pages as $page )
{
// Is the current node a child of the parent we are currently populating?
if ( $page->parent_id == $parentId )
{
// Is there an array for the current parent?
if ( !isset( $parentArr[ $page->id ] ) )
{
// Nop, create one so the current parent's children can
// be inserted into it.
$parentArr[ $page->id ] = array();
}
// Call the function from within itself to populate the next level
// in the array:
addChildren( $get_pages, $parentArr[ $page->id ], $page->id );
}
}
}
$result = array();
addChildren( $get_pages, $result );
print_r($result);
This is not the most efficient way to go but for a small number of pages & hierarchies you should be fine.

SQL result to PHP multidimensional array

I'm retrieving some hierarchical data from an Oracle database using the "connect by" function.
Then I populate a PHP array with the result of my query looking like:
while ($row_branches = oci_fetch_array($query_tree)) {
$tree[] = array(
'id' => $row_branches['ID']
, 'parent' => $row_branche['PARENT']
, 'data' => htmlspecialchars($row_branches['NAME'])
, 'level' => $row_branches['LEVEL']
);
}
The field ID is the unique id of the row
The field PARENT is the ID of the parent
The field DATA is the name of the item
The field LEVEL is the level of the row in the hierarchy.
I'd rather have a multidimensional array because my goal is to use the PHP function json_decode().
The depth of the hierarchy is never known in advance.
So my question is:
How could I populate a multidimensional array with the result of my query?
Thanks a million in advance for your answers.
try this
function adj_tree(&$tree, $item) {
$i = $item['ID'];
$p = $item['PARENT'];
$tree[$i] = isset($tree[$i]) ? $item + $tree[$i] : $item;
$tree[$p]['_children'][] = &$tree[$i];
}
$tree = array();
while ($row = oci_fetch_array($query_tree)) {
adj_tree($tree, $row);

Categories