How to set sub json array in one array PHP - php

I am new in php, I was trying to fetch data that I get from the following response but I want to set this data in sub array. How to do this? I have two different tables category and Product. How to Show Multiple Products Category wise.
Thanks in Advance!
{
"data" : [
{
"id" : "1",
"recipe_name" : "Tofu Tikka",
"ingredients" : "Firm tofu 1 pack (bite sized cube)\r\n",
"prepration" : "Press tofu with the help of plate to remove moisture
and leave for 30-40 minutes, then cut in cubes.\r\n",
"category_id":"1",
"category_name":"Today's Menu"
}
]
}
How to set above Response in sub Array like following way
{
"data":[
"category_id":"1",
"category_name":"Today's Menu"
"recipes::[
{
"id":"1",
"recipe_name":"Tofu Tikka",
"ingredients":"Firm tofu 1 pack ",
"prepration":"Press tofu with the help of plate"
}, {
"id":"2",
"recipe_name":"Tikka Paneer",
"ingredients":"Firm tofu 1 pack ",
"prepration":"Press tofu with the help of plate"
},
]
]
}
Below is my PHP File
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
// initialize object
$product = new Product($db);
// query products
$stmt = $product->read();
$num = $stmt->rowCount();
// check if more than 0 record found
if ($num>0) {
// products array
$products_arr=array();
$products_arr["data"]=array();
// retrieve our table contents
// fetch() is faster than fetchAll()
// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// extract row
// this will make $row['name'] to
// just $name only
extract($row);
$product_item=array(
"id" => $id,
"recipe_name" => $recipe_name,
"ingredients" => html_entity_decode($ingredients),
"prepration" => $prepration,
"category_id" => $category_id,
"category_name" => $category_name
);
array_push($products_arr["data"], $product_item);
}
echo json_encode($products_arr);
} else {
echo json_encode(
array("message" => "No products found.")
);
}
?>

In your while loop, you can group the recipes first via category_id instead of pushing the whole row array. Then re-index using array_values().
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// extract row
// this will make $row['name'] to
// just $name only
extract($row);
// Check if category_id is already set
if (!array_key_exists($category_id, $products_arr["data"])) {
$products_arr["data"][$category_id] = array(
"category_id" => $category_id,
"category_name" => $category_name,
"recipes" => []
);
}
// Push the recipe details
$products_arr["data"][$category_id]["recipes"][] = array(
"id" => $id,
"recipe_name" => $recipe_name,
"ingredients" => html_entity_decode($ingredients),
"prepration" => $prepration
);
$products_arr["data"] = array_values($products_arr["data"]);
}
echo json_encode($products_arr);
Note: The output is a little bit different from your expected result. Because the output's data key has arrays based on categories instead of having category_id. Preventing more than one category from overwriting if you use category_id as key inside data

I will suggest you to use JOIN while getting records of category and its related products. It will need single query and single loop to generate array you want. Here is the sample query which you can use. It will get category name with each product record and do not show those categories who do not have products in it.
SELECT * FROM categories AS c LEFT JOIN offers AS p ON c.category_id=p.category_id WHERE p.offer_id IS NOT NULL
Note: - Do not use asterisk (*) in your search query, use table field names instead.
<?php
// initialize empty category array
$categoryArr = [];
// $row has product info with category id and name in it.
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
/* First key of categoryArr variable is category id. It will automatically create array key for each category.
* If an array key already exists, it will add prodcts in it.
*/
$categoryArr[$row['category_id']]['category_id'] = $row['category_id'];
$categoryArr[$row['category_id']]['category_name'] = $row['category_name'];
$categoryArr[$row['category_id']]['products'][] = $row;
}
/* Once loop done with its work. Need to reset array keys with the help of below function. */
$result = array_values($categoryArr);
echo json_encode($result); ?>
I have not tested it, its just to give you an idea. I hope you will improve it.

// I hope it's useful ..
$returnArr = array('category_id' => $category_id,'category_name' => $category_name,$products_arr["data"]); // in last "$products_arr["data"]" set your dynamic code ..
$arr = array('recipes' => $returnArr);
echo json_encode($arr['recipes']); // print json ..

Related

Fill one array using two loop

I have an object where there are all my articles.
I'm currently looping my object to fill an array where I create an associative table for each article.
In my object I also have a Categories object and I would like to add the label of each category at the end of each associative array previously completed, but
I don't know how to do that.. In the Categories object there may be multiple labels.
My code :
$articles = $this->entityManager->getRepository('SGBundle:Article')->findBy([], ['id'=>'desc']);
$arrayCollection = [];
foreach($articles as $article) {
$arrayCollection[] = [
'id' => $article->getId(),
'date_publication' => $article->getDatePublication(),
...
];
foreach($article->getCategories() as $categorie) {
$arrayCollection[] = ['categorie' => $categorie->getLibelle()];
}
}
On my screenshot, for each article there is an array with 36 values ​​and an array with 1 value and I would like this table to be in the table where there are 36 values. It's possible ?
First gather categories, then add'em to article item:
foreach($articles as $article) {
$categories = [];
foreach($article->getCategories() as $categorie) {
$categories[] = $categorie->getLibelle();
}
$arrayCollection[] = [
'id' => $article->getId(),
'date_publication' => $article->getDatePublication(),
...
//
'categorie' => $categories,
];
}
If the article.categories field is marked as lazy, then it won't be hydrated by default and the $article->getCategories() will perform a new query on each loop round.
Instead of a simple findBy, you might want a custom DQL query in this case to optimize this and get the exact array you want in one single request.
Also note that your current query is fetching all articles of your database. While this is probably your purpose, keep in mind that this could get pretty heavy with the data growing. In most cases, this kind of query should be paginated.

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.

Grab more out multidimensional array to put in recursive foreach function

I am trying to learn more about multi-dimensional arrays along with recursive functions so as an exercise I have a threaded comments section. each comment (in the database) has an id, parent id (0 by default, but will be the id of the comment that it is in reply to), and content plus more.
I have followed a tutorial and come up with a half complete solution, however I can only grab a portion of the array's data with my current solution. I want to be able to grab the extra information such as 'authorId', 'commentDate' and everything I have tried thus far to do so has resulted in massive failure. Here is my code so far, the is the recursive function (within a class):
function makeList($parentId) {
// Need the main $comms array:
global $comms;
echo '<ul>'; // Start an unordered list.
// Loop through each subarray:
foreach ($parentId as $comm_id => $theCommName) {
// Display the comment:
echo "<li>".$theCommName;
// Check for sub comments:
if (isset($comms[$comm_id])) {
// Call this function again:
self::makeList($comms[$comm_id]);
}
echo '</li>'; // Complete the list item.
} // End of FOREACH loop.
echo '</ul>'; // Close the ordered list.
} // End of function.
and here is another function that will connect to the database to retrieve comments, and make use of the previous function:
function callCommentList($pid){
// Connect to the database:
$dbc = mysqli_connect(HOST_NAME, USERNAME, PASSWORD, DB_NAME);
// Retrieve all the comments from a particular post:
$q = 'SELECT id, parentId, content, authorId, postId, commentDate, approved FROM comments WHERE postId='.$pid.' AND approved=1 ORDER BY parentId, commentDate ASC';
$r = mysqli_query($dbc, $q);
// Initialize the storage array:
global $comms;
$comms = array();
// Loop through the results:
while (list($commsId, $commParentId, $theComm, $authorId, $postId, $commentDate, $approved) = mysqli_fetch_array($r, MYSQLI_NUM)) {
// Add to the array:
$comms[$commParentId][$commsId] = $theComm;
}
self::makeList($comms[0]);
}
and on another page I have created the instance of the class and called the method:
$post->callCommentList($post->getId())
Here is the result (the unordered list):
Ideally however, I would also like to get other information pulled from the database such as authorId etc and display it with the comment(and more). Any idea on how to go about doing that?
Ok well, I was going about storing items into the array wrong.
In my original code, I stored JUST the comment contents three levels deep, however I realised I could also store other things I needed three levels deeps (the author id + comment date), and did that as such:
while (list($commsId, $commParentId, $theComm, $authorId, $postId, $commentDate, $approved) = mysqli_fetch_array($r, MYSQLI_NUM)) {
// Add to the array the comment, the comment's author, the comment's date:
$comment = array($theComm, $authorId, $commentDate);
$comms[$commParentId][$commsId] = $comment;
}
which will equal this when the array is printed neatly:
Array
(
[0] => Array
(
[1] => Array
(
[0] => Comment One
[1] => 3
[2] => 2014-07-06 21:16:19
)
[4] => Array
(
[0] => Third Comment That does not reply to anything
[1] => 3
[2] => 2014-07-06 21:24:12
)
)
[1] => Array
(
[2] => Array
(
[0] => Comment That's In Response To Comment One
[1] => 3
[2] => 2014-07-06 21:17:03
)
)
)
so from there I could easily see that I could just grab the details via the index, so the revised recursive method is as follows:
function makeList($parentId) {
// Need the main $comms array:
global $comms;
echo '<ul>'; // Start an unordered list.
// Loop through each subarray:
foreach ($parentId as $comm_id => $theComm) {
// Display the item:
echo "<li>";
echo "<strong>Id:</strong> ".$comm_id."<br/>";
echo "<strong>The Comment</strong> : ".$theComm[0]."<br/>";
echo "<strong>Author Id:</strong> ".$theComm[1]."<br/>";
echo "<strong>Comment Date:</strong> ".$theComm[2];
// Check for comments:
if (isset($comms[$comm_id])) {
// Call this function again:
self::makeList($comms[$comm_id]);
}
echo '</li>'; // Complete the list item.
} // End of FOREACH loop.
echo '</ul>'; // Close the unordered list.
}
and now I have access to all the array elements I need:
just need to clean up the code (and use PDO instead for the communicating with the database)

PHP MySQL building a 3 Tier multi dimensional array

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

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