Convert a 2D array to JSON in PHP - php

My goal is to make a single database hit to generate a JSON array of objects with attributes that could be also be an array of objects, which could also have attributes that array of objects etc of an arbitrary (but known) depth.
I get a 2D array from my database using a PDO object.
$stmt = $this->pdo->prepare($sql);
$stmt->execute($args);
$TwoDimArray = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $TwoDimArray;
So in my example, I have a Quiz, that can have questions, that can have answers. So a depth of 3. So assuming I have a 2D Array such as the table below, how would I make this JSON array using that data. (Note: other data has been removed for clarity sake, but questions and answers could have other attributes.)
Edit: This is my attempt. It is horribly inefficient and not very abstract for the general case but this code will achieve the right answer for small data sets.
$data = ($database -> query($sql,$args)); // the result is $TwoDimArray
$quizes = array();
$quiz_id_list = array();
foreach($data as $quizkey => $quizvalue){
if(!in_array($quizvalue["quiz_id"], $quiz_id_list)) {
array_push($quiz_id_list, $quizvalue["quiz_id"]);
$question_id_list = array();
$questions = array();
foreach ($data as $questionskey => $questionsvalue) {
if ($quizvalue["quiz_id"] == $questionsvalue["quiz_id"] && !in_array($questionsvalue["question_id"], $question_id_list)) {
$answers = array();
array_push($question_id_list, $questionsvalue["question_id"]);
foreach ($data as $answerskey => $answersvalue) {
$myanswer = array();
if ($questionsvalue["question_id"] == $answersvalue["question_id"]) {
$myanswer["answer_id"] = $answersvalue["answer_id"];
array_push($answers, $myanswer);
}
}
$myquestion = array();
$myquestion["question_id"] = $questionsvalue["question_id"];
$myquestion["answers"] = $answers;
array_push($questions, $myquestion);
}
}
$myquiz = array();
$myquiz["quiz_id"] = $quizvalue["quiz_id"];
$myquiz["questions"] = $questions;
array_push($quizes, $myquiz);
}
}
return json_encode($quizes);
The contents of $data looks like this:
array (
0 =>array('quiz_id' => '1', 'question_id' => '1', 'answer_id' => '1',),
1 =>array('quiz_id' => '1', 'question_id' => '1', 'answer_id' => '2',),
...
5 =>array('quiz_id' => '1', 'question_id' => '2', 'answer_id' => '6',),
6 =>array('quiz_id' => '1', 'question_id' => '2', 'answer_id' => '7',),
...
22 =>array('quiz_id' => '2', 'question_id' => '6', 'answer_id' => '23',),
23 =>array('quiz_id' => '2', 'question_id' => '6', 'answer_id' => '24',),
)
The result should return a json object that looks like this:
[
{
"quiz_id": 1,
"questions": [
{"question_id":1, "answers": [{"answer_id":1}, {"answer_id":2}, {"answer_id":3},{"answer_id":4}]},
{"question_id":2, "answers": [{"answer_id":5}, {"answer_id":6}, {"answer_id":7},{"answer_id":8}]},
{"question_id":3, "answers": [{"answer_id":9}, {"answer_id":10}, {"answer_id":11},{"answer_id":12}]}
]
},
{
"quiz_id": 2,
"questions": [
{"question_id":4, "answers": [{"answer_id":13}, {"answer_id":14}, {"answer_id":15},{"answer_id":16}]},
{"question_id":5, "answers": [{"answer_id":17}, {"answer_id":18}, {"answer_id":19},{"answer_id":20}]},
{"question_id":6, "answers": [{"answer_id":21}, {"answer_id":22}, {"answer_id":23},{"answer_id":24}]}
]
}
]

You say this is the contents of $TwoDimArray There is not much that can be done with it. I suspect there is something missing yet.
array ( 'quiz_id' => '1', 'question_id' => '1', 'answer_id' => '1', ),
array ( 'quiz_id' => '1', 'question_id' => '1', 'answer_id' => '2', ),
array ( 'quiz_id' => '1', 'question_id' => '1', 'answer_id' => '3', ),
This will get rid of your "redundant data":
foreach($TwoDimArray as $value){
$quiz[$value['quiz_id']][$value['question_id']][$value['question_id']] = 1;
}

Related

Codeigniter 4: Merge arrays then use InsertBatch to insert data in MySQL

I'm trying to insert multiple rows into MySQL using the 'InsertBatch' function. However, I am unable to make it work. I'm new to this, and I'm not sure if I'm doing it correctly.
I'm using input and select fields with $is data and a table with $tmp data. I used foreach and for statements to get the $tmp_data on the table. An array push() was also used to merge the data into an array.
public function Add_Fees_Matrix() {
$fm_model = new Mod_Fees_Matrix();
$data = [];
//input and select type
$is_data = [
'fm_code' => $this->request->getPost('fm_code'),
'sy_id' => $this->request->getPost('sy_id'),
'dept_id' => $this->request->getPost('dept'),
'gl_id' => $this->request->getPost('gl_id'),
'ppl_id' => $this->request->getPost('ppl_mode')
];
//table
$tmp_data = [
'fcp_description' => $_POST['fcp_description'],
'fmf_amount' => $_POST['fmf_amount']
];
foreach ($tmp_data as $k => $v) {
for($i = 0; $i < count($v);$i++) {
array_push($data, $is_data);
$data[$i][$k] = $v[$i];
}
}
echo "<pre>";
var_export($data);
$fm_model->insertBatch($data);
}
In my output, it generates four arrays. However, only the first two arrays are considered necessary. I think the problem is caused by the array push() function.
Here's the output of var_export():
array (
0 =>
array (
'fm_code' => 'FM-1741195162687292',
'sy_id' => '2',
'dept_id' => '1',
'gl_id' => '2',
'ppl_id' => '1',
'fcp_description' => 'INSTITUTIONAL DEVELOPMENT FEE',
'fmf_amount' => '123',
),
1 =>
array (
'fm_code' => 'FM-1741195162687292',
'sy_id' => '2',
'dept_id' => '1',
'gl_id' => '2',
'ppl_id' => '1',
'fcp_description' => 'MATRICULATION',
'fmf_amount' => '1230',
),
2 =>
array (
'fm_code' => 'FM-1741195162687292',
'sy_id' => '2',
'dept_id' => '1',
'gl_id' => '2',
'ppl_id' => '1',
),
3 =>
array (
'fm_code' => 'FM-1741195162687292',
'sy_id' => '2',
'dept_id' => '1',
'gl_id' => '2',
'ppl_id' => '1',
),
)
Upon clicking a button, can someone help me to insert the data on my database?
This seems to work in my problem.
public function Add_Fees_Matrix() {
$fm_model = new Mod_Fees_Matrix();
$data = [];
$tmp_data = [
'fcp_description' => $this->request->getPost('fcp_description'),
'fcp_amount' => $this->request->getPost('fmf_amount')
];
foreach ($tmp_data as $k => $v) {
for($i = 0; $i < count($v);$i++) {
$data[$i]['fm_code'] = $this->request->getPost('fm_code');
$data[$i]['sy_id'] = $this->request->getPost('sy_id');
$data[$i]['dept_id'] = $this->request->getPost('dept');
$data[$i]['gl_id'] = $this->request->getPost('gl_id');
$data[$i]['ppl_id'] = $this->request->getPost('ppl_mode');
$data[$i][$k] = $v[$i];
}
}
$fm_model->insertBatch($data);
echo "<pre>";
var_export($data);
}

convert normal array in nested array with php

I have a hierarchical database table like below
ID Name Subcategory ParentID
1 ABC 0
2 DEF QFE 0
3 QFE XYZ 2
4 XYZ MNJ 3
From Thant I have got PHP array like below
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => 'QFE', 'ParentID' => '0'),
array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => 'XYZ', 'ParentID' => '2'),
array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3')
);
but I want array like below
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3'), 'ParentID' => '2'), 'ParentID' => '0'),
);
I want a function which checks is that row have some Subcategory or not and if a row has Subcategory then get that subcategory row as an array and make one array with all category and Subcategory
for that, I have tried to make a function which is given below
function find_subcategory($ID,$con){
$table_name ="SELECT * FROM `table_name` WHERE `parent_id` = '$ID'";
$table_name_result = mysqli_query($con,$table_name);
$category_array = array();
if(mysqli_num_rows($table_name_result)) {
while($row = mysqli_fetch_assoc($table_name_result)) {
$Subcategory= $row['Subcategory'];
$ID = $row['ID'];
if ($Subcategory== '') {
$find_subcategory = find_subcategory($ID,$con);
$row['Subcategory'] = $find_subcategory;
$category_array[] = $row;
}else{
$category_array[] = $row;
}
}
}
return json_encode(array('tbl_category'=>$category_array));
}
but this function is not working to get all the subcategories of one category.
can anybody help me with this
Rather than create a recursive routine, which executes the SQL for each level, this instead reads all of the categories in and them assembles them into the hierarchy.
Note that it reads them in reverse order so that when it assembles them, each subcategory is always read before the parent (More details in code comments)...
$table_name ="SELECT * FROM `category` ORDER BY parent_id DESC, id desc";
$table_name_result = mysqli_query($con,$table_name);
$categories = mysqli_fetch_all($table_name_result, MYSQLI_ASSOC);
$output= [];
foreach ( $categories as $category) {
// If there is a parent for this item
if ( !empty ($category['parent_id']) ) {
// Set basic details
$output[$category['parent_id']]['Subcategory'][$category['id']] = $category;
// If there is already some data (subcategories)
if ( isset($output[$category['id']]) ){
// Copy subcategories
$output[$category['parent_id']]['Subcategory'][$category['id']] +=
$output[$category['id']];
// Remove old node
unset ( $output[$category['id']] );
}
}
else {
// Add in category data (allow for existing data to be added
$output[$category['id']] = $category + ($output[$category['id']]??[]);
}
}
I successfully implemented and tested a recursive routine to solve this. However, for performance reasons I had to decouple the access to the database from the recursive call.
First, you fetch your query into an array as you already have and then recursively rearrange the elements so that the keys are nested in the proper order.
Pretty much of the explanations I'd like to put here are put as comments in the code.
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => 'QFE', 'ParentID' => '0'),
array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => 'XYZ', 'ParentID' => '2'),
array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3'),
array('ID' => '5', 'Name' => 'XYY', 'Subcategory' => 'MNJ', 'ParentID' => '1')
);
// recreate nested array
function get_nested_array($arr) {
$new_arr = array(); // new array to collect each top level element with nesting
foreach ($arr as $key => $value) {
// only top level elements would appear here as they would not be nested
if($value['ParentID'] == '0') {
array_push($new_arr, get_nested_item($value, $arr));
}
}
return $new_arr;
}
// recursive function to perform nesting on each element
function get_nested_item($hay, $stack) {
foreach ($stack as $key => $value) {
if ($hay['ID'] == $value['ParentID']) {
$index = get_key($hay, $stack);
// reduce $stack size by removing the HAY from the STACK
// recursion terminates when $stack size is 0
$stack = $index >= 0 ? array_splice($stack, $index) : [];
// update subcategory of the found nesting
$hay['Subcategory'] = get_nested_item($value, $stack);
}
}
return $hay;
}
// get the position of $hay in a $stack using the ID
function get_key($hay, $stack) {
foreach ($stack as $key => $value) {
if($hay['ID'] == $value['ID']) return $key;
}
return -1;
}
// print array so that it understandable
function print_array($arr) {
foreach ($arr as $key => $value) {
print_r($value);
echo "<br>";
}
}
// Test case
// print array before nesting
print_array($array_name);
echo"<br>";
// print array after nesting
$new_array = get_nested_array($array_name);
print_array($new_array);

MySQL PDO fetchAll as array with format

I have this PDO code
function getAllUserTicketHistoryJson($rid){
global $conn;
$stmt = $conn->prepare("SELECT user_id, total_ticket FROM lottery_user WHERE round_id = :rou");
$stmt->bindParam(':rou', $rid);
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$res = $stmt->fetchAll();
return $res;
}
and show the data in my index php file like this one
$getAllUserTicketHistoryJson = getAllUserTicketHistoryJson($getRound['id']);
And call all the data to this one
foreach($getAllUserTicketHistoryJson as $key => $value){
$array=$value;
}
when I try to var_export($value); the data show like this
array ( 'user_id' => '1', 'total_ticket' => '1', )array ( 'user_id' => '2', 'total_ticket' => '50', )array ( 'user_id' => '3', 'total_ticket' => '10', )array ( 'user_id' => '4', 'total_ticket' => '5', )
My question is, can I get the data display in one array?
should be like this
array("1" => 1, '2' => 50, '3' => 10, '4' => 5)
how to get the data become inside one array only?
Found the answer, we need a custom format in foreach.
so the code will be like this
$data = array();
foreach($getAllUserTicketHistoryJson as $value){
$data[$value['user_id']] = number_format((float)($value['total_ticket'] / $getAllTicketRound * 100), 2, '.', '');
}

Merge arrays of associative arrays by shared column values [duplicate]

This question already has answers here:
Merge two 2d arrays by shared column value
(6 answers)
Closed last month.
I want to merge two arrays based on a common column value. Here are my 2 arrays:
$array1 = [
[
"total_process_per_category" => "6",
"category_id" => "1"
],
[
"total_process_per_category" => "2",
"category_id" => "2"
]
];
$array2 = [
[
"total_pinned_per_category" => "16",
"category_id" => "1"
],
[
"total_pinned_per_category" => "4",
"category_id" => "2"
]
];
I want to merge these arrays to get:
array (
0 =>
array (
'total_process_per_category' => '6',
'total_pinned_per_category' => '16',
'category_id' => '1',
),
1 =>
array (
'total_process_per_category' => '2',
'total_pinned_per_category' => '4',
'category_id' => '2',
),
)
As you can see, the two arrays have the same key ['category_id'] and same value as well.
I want to make a result where ['total_process_per_category'] and ['total_pinned_per_category'] are placed together on the same array based on their ['category_id'] value.
I got this using a nested foreach, but it looks so ugly. Please show me a better way.
you can try array_reduce:
$someVariable = 'someValue';
$result = array_reduce(array_merge($array1, $array2), function ($carry, $item) use ($someVariable) {
if (isset($carry[$item['category_id']])) {
$carry[$item['category_id']] = array_merge($carry[$item['category_id']], $item);
} else {
$carry[$item['category_id']] = $item;
}
return $carry;
}, array());
var_dump($result);
This can be done without an "ugly nested foreach". Merge the two arrays before iterating, the group by the category_id values. After the loop, clear away the temporary first-level keys with array_values().
Code: (Demo) (array_reduce() version)
$result = [];
foreach (array_merge($array1, $array2) as $row) {
$result[$row['category_id']] = ($result[$row['category_id']] ?? []) + $row;
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'total_process_per_category' => '6',
'category_id' => '1',
'total_pinned_per_category' => '16',
),
1 =>
array (
'total_process_per_category' => '2',
'category_id' => '2',
'total_pinned_per_category' => '4',
),
)
Do you want something like:
foreach ( $array1 as $index => $value ) {
$mergeArray[] = [ $value, $array2[$index]];
}

Processing data from query

I'm writing a 'get' function in a model class in codeigniter, but I need to process some of the data as it's returned, ideally without a whole bunch of overhead.
function get_answers($p)
{
$result = $this->db->get_where('answer', array('a_upid_fk' => $p))->result();
// foreach ($result->answer as $ans) {
// $result->answers = explode( '|', $ans, -1 );
// }
return $result;
}
The results look like this:
array (
0 =>
stdClass::__set_state(array(
'aid' => '742',
'a_upid_fk' => '231',
'answer' => '4555|||',
'a_qid_fk' => '70',
'created' => '2012-04-20 15:35:38',
'last_modified' => '2012-04-20 15:36:11',
'revision' => '1',
)),
1 =>
stdClass::__set_state(array(
'aid' => '743',
'a_upid_fk' => '231',
'answer' => NULL,
'a_qid_fk' => '71',
'created' => '2012-04-20 15:35:38',
'last_modified' => '2012-04-20 15:35:38',
'revision' => '1',
)) ...
the problem is the answer is stored as a pipe delimited list of answers, but I want the function to return it as an exploded array instead. I'm not sure of the syntax and how to create and replace or append the array to the array of objects I've pasted above.
You can see some code I've been trying commented out.
Ideally instead of 'answer' => '4555|||',
I would like to have
'answer' => array (
0 => '4555',
1=> '',
2=> '')
I have no problem making the array using explode but I'm not sure how to modify the original codeigniter active-record result.
Loop thru your sub-arrays:
$answer_array = explode('|', $answer);
foreach ($aswer_array as $instance)
{
$result[] = $instance;
}
Define __set_state()), call it using - $subarray = $result[0][$object->answer].

Categories