getting relational results from three tables into one nested array - php

i have googled for solution to my problem but nun helped me.
here i have three tables items, feeds and images. each item has one feed and one or more images.
i have 3 functions. one is to return records from items table the second one receives feeds_id (foreign key in items table) then return records from feeds table. the third function is to return all images related to items_id.
those functions are :
* To get all items in database:
function get_items(){
return $query = Database::getInstance('db')
->table('items')
->columns(
'id',
'items.rowid',
'items.feed_id as feed_id',
'title' )
->findAll();
}
* To get feed data from feeds table :
function get_feeds($id){
return $query = Database::getInstance('db')
->table('feeds')
->eq('id',$id)
->findAll();
}
* To get image data from images table :
function get_images($id){
return $query = Database::getInstance('db')
->table('images')
->columns('items_id','src as image_url',
'title as image_title',
'alt')
->eq('items_id',$id)
->findAll();
}
Then i have the following code to call those function and display the result in jsonformat:
$response['items'] = array();
$response['feeds'] = array();
$response['images'] = array();
foreach ($items = get_items() as $item) {
$response['items'][] = array(
'id' => (int)$item['rowid'],
'feed_id' => (int)$item['feed_id'],
'title' => $item['title'],
);
foreach ($feeds = get_feeds((int)$item['feed_id']) as $feed) {
$response['feeds'][] = array(
'title' => $feed['title'],
'logo_url' => $feed['logo_url'],
'site_url' => $feed['site_url'],
);
}
foreach ($images = get_images($item['id']) as $image) {
$response['images'][] = array(
'id' => $image['items_id'],
'url' => $image['image_url'],
'thumb' => $_SERVER['SERVER_NAME'] . /myServer/images/thumbs/'. 'thumb_'.basename($image['image_url']),
'title' => $image['image_title'],
'alt' => $image['alt']
);
}
}
echo json_encode($response, JSON_PRETTY_PRINT);
so, my expectation is to get json output like:
"items": [
{
"id": ,
"feed_id":
"title":
"feeds": [
{
"title": ,
"logo_url": ,
"site_url": "
}
]
"images": [
{
"id": ,
"url": ",
"thumb":
"title": "",
"alt": ""
},
{
....
}
]
}]
i mean each item array should include nested arrays of its related data coming from get_feeds and get_images functions.
instead of that, i get response like :
//here i select two items from my db
"items": [
{ //first_item
"id": ,
"feed_id":
"title":
},
{ //second_item
"id": ,
"feed_id":
"title":
}
],
"feeds": [
{ // feed data for first item
"title": ,
"logo_url": ,
"site_url": "
},
{ // feed data for second item
"title": ,
"logo_url": ,
"site_url": "
}
],
"images": [
{ // image data for first item
"id": ,
"url": ",
"thumb":
"title": "",
"alt": ""
},
{ // other images data
....
}
]
}]
as you see i am getting output without keeping relation between items, feeds and images, all of them are shown independently.
my queries are fine but i am suspecting error in my foreach statements.
i could fix this issue by joining those tree tables in one query, but i don't want to do that because i need to do validation and other operations to output comes from each table.
i appreciate your help

i found the solution. it is very easy :)
it is just like:
$response['items'][] = array(
'id' => (int)$item['rowid'],
'feed_id' => (int)$item['feed_id'],
'title' => $item['title'],
'feeds' => array(
)
'images' => array(
)
);

Related

How can I build an object/array?

I am rather new to PHP so I don't know how to work with these datasets. I make a MySQL select and get back an object like this:
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 1,
"dailyworkhourssum": "7.70"
},
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 3,
"dailyworkhourssum": "1.2"
},
{
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": "7.70"
},
I want to iterate through this and in the end it should look like this:
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid1": true,
"categorid3": true,
"dailyworkhourssum1": "7.70",
"dailyworkhourssum3": "1.2"
},
{
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": "7.70"
},
What this does is that it merges tow fields together (if they have the same bookingdate )into one so that I can display it in a table without reoccurring dates.
My problem:
I don't know what this type of data is called.
I don't know how to create something like this.
I can add fields to this type of data with $data->newField = example so I think that this is an object.
In JS it's called an object, but in PHP you will use an associative array instead.
In your case, I think, you have an array of associative arrays. It looks like this:
$books = [
[
"membername" => "NAME",
"bookingdate" => "2020-02-03",
"categoryid" => 1,
"dailyworkhourssum" => "7.70"
],
[
"membername" => "NAME",
"bookingdate" => "2020-02-03",
"categoryid" => 3,
"dailyworkhourssum" => "1.2"
],
[
"membername" => "NAME",
"bookingdate" => "2020-02-05",
"categoryid" => 3,
"dailyworkhourssum" => "7.70"
]
];
If you wanna merge an arrays with the same "bookingdate" then I recommend you to loop through this array and add its elements to another associative array with bookingdates as keys, and check, in case if there is such key already, then merge the arrays, like this:
$merged = [];
foreach ($books as $book) {
$date = $book['bookingdate'];
if (isset($merged[$date])) {
$merged[$date] = $merged[$date] + $book;
} else {
$merged[$date] = $book;
}
}
I think that it is not a valid code (no time, sorry), but I hope, you cautch the idea.
If you want a 'list' instead of an associative array, than you can do this:
$mergedList = array_values($merged);
Thus you will rid of string keys.
If I understood correctly, you obtain a table with 4 columns an a variable number of rows and you want to transform it to a table with a variable number of columns. For that, using a data structure where every item is different from the previous one can make everything harder than it needs. I'd suggest you use a fixed structure:
// I'm assuming you have a PHP array as starting point
$input = [
[
'membername' => 'NAME',
'bookingdate' => '2020-02-03',
'categoryid' => 1,
'dailyworkhourssum' => '7.70',
],
[
'membername' => 'NAME',
'bookingdate' => '2020-02-03',
'categoryid' => 3,
'dailyworkhourssum' => '1.2',
],
[
'membername' => 'NAME',
'bookingdate' => '2020-02-05',
'categoryid' => 3,
'dailyworkhourssum' => '7.70',
],
];
$output = [];
foreach ($input as $data) {
// We'll group by booking date
if (!isset($output[$data['bookingdate']])) {
$output[$data['bookingdate']] = [
'membername' => $data['membername'],
'bookingdate' => $data['bookingdate'],
'categoryid' => $data['categoryid'],
'dailyworkhourssum' => [],
];
}
// A single date may have several daily work hours
$output[$data['bookingdate']]['dailyworkhourssum'][] = $data['dailyworkhourssum'];
}
// We discard array keys (we only needed them to group)
echo json_encode(array_values($output));
[{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 1,
"dailyworkhourssum": ["7.70", "1.2"]
}, {
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": ["7.70"]
}]
Wherever you consume this JSON you just need to loop the dailyworkhourssum array. You may also want to loop the entire structure before printing the table and keep a counter in order to determine the maximum number of columns so you can draw empty cells where needed (tables are rectangular).

slack, php and json - Valid Markup for iterating app selections

I've been trying to create a slack app which takes the basic information of the name and sku of the product and places it within a select box that appears in slack. Unfortunately my code to populate the valid json is going wrong somewhere when i try to itterate using a loop.
Valid Json is here:
{
"text": "Great! You want to find something!",
"attachments": [
{
"text": "Please type what you want to find",
"fallback": "Sorry! Cant do that at the moment!",
"callback_id": "cg_selectproduct",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "cg_choice",
"text": "Find Product",
"type": "select",
"options": [
{
"text": "option1",
"value": "option1"
},
{
"text": "option2",
"value": "option2"
},
{
"text": "option3",
"value": "option3"
}]
}
]
}
]
}
This works perfectly fine without the iteration. I have no issues if i tell the app to go here. It displays all options correctly.
Invalid PHP
$check = ($dbh->prepare("SELECT * FROM product_list WHERE FAMILY='PARENT'"));
$check->execute();
$row = $check->fetchAll();
// execute a pdo search to find all product parents
$jsonInput = "";
foreach($row as $rows){
$jsonInput .= '"text"=>"' . $rows['PRODUCT_NAME'] . '", "value" => "' . $rows['SKU'] . '",';
}
$jsonInput = rtrim($jsonInput, ',');
//Create an iterative string which will contain the product names and skus, removing the comma at the end.
header('Content-Type: application/json');
//Set the content type to json
$optionSelect = array(
"text" => "Great! You want to find something!",
"attachments" =>array(
"text" => "Please type what you want to find",
"fallback" => "Sorry! Cant do that at the moment!",
"callback_id" => "cg_selectproduct",
"color"=> "#3AA3E3",
"attachment_type" => "default",
"actions" => array(
"name" => "cg_choice",
"text" => "Find Product",
"type" => "select",
"options" => array($jsonInput)
)
)
);
//Create and itterate the options for the selection so it's populated
print_r(json_encode($optionSelect));
//print to show json
I'm not 100% sure where i'm going wrong with this. Maybe i'm thinking about a minor part a little too much. Can anyone here help me with where i'm going wrong?
$jsonInput = [];
foreach($row as $rows) {
$jsonInput[] = array(
'text' => $rows['PRODUCT_NAME'],
'value' => $rows['SKU']
);
}
// ...........
"options" => $jsonInput

Laravel php get last element in multidimensional array

I have the following json file with products details:
"products": [
{
"sku": 123,
"name": "iphone 7",
"categoryPath": [
{
"id": "abcat0800000",
"name": "Cell Phones"
},
{
"id": "pcmcat209400050001",
"name": "All Cell Phones with Plans"
}
],
}
]
I would like only to store the last value (ID and NAME) of the categoryPath Array:
"id": "pcmcat209400050001",
"name": "All Cell Phones with Plans"
My current code takes the json file, decode the json and insert in products table the information.
$json = File::get("/json/cell-0.json");
$data = json_decode($json);
$array1 = (array)$data;
//table products
foreach ($array1['products'] as $obj) {
DB::table('products')->insert(array(
'productSku' => ((isset($obj->sku) ? $obj->sku : 1)),
'productName' => ((isset($obj->name) ? $obj->name : null)),
'categoryId' => end($obj->categoryPath->id),
'categoryName' => end($obj->categoryPath->name)
));
Taking into consideration that array->categoryPath have multiple fields I would like to use a function (eg: end()) in order to take id and name only of the last values.
Using end($obj->categoryPath->id) I receive the following error ->
Attempt to modify property of non-object
Is this the best way to retrieve the last value of a multidimensional array?
You could use end() probably but your accessors would have to be outside the end() call (untested):
foreach ($array1['products'] as $obj) {
DB::table('products')->insert(array(
'productSku' => ((isset($obj->sku) ? $obj->sku : 1)),
'productName' => ((isset($obj->name) ? $obj->name : null)),
'categoryId' => end($obj->categoryPath)->id,
'categoryName' => end($obj->categoryPath)->name
));
The way you're getting the last element is incorrect, here is the refactored code. I also eliminated the need to cast data as an array as well.
$json = File::get("/json/cell-0.json");
$data = json_decode($json, true);
//table products
foreach ($data['products'] as $product) {
$lastCategory = isset($product['categoryPath']) && $size = sizeof($product['categoryPath']) ? $product['categoryPath'][$size-1] : array('id' => null, 'name' => null);
DB::table('products')->insert(
array(
'productSku' => isset($product['sku']) ? $product['sku'] : 1,
'productName' => isset($product['name']) ? $product['name'] : null,
'categoryId' => lastCategory['id'],
'categoryName' => lastCategory['name']
)
);
}

How to create json string given below

I am android developer and new in PHP. I don't know PHP very well. I create
<?php
header('Content-Type: application/json; charset=utf-8');
$mysqli = new mysqli ('localhost', 'mabhi', '9993', 'general');
//PROBLEM LANGUAGE ?????
if (function_exists('mysql_set_charset')) {
mysqli_set_charset($mysqli, 'utf8');
} else {
mysqli_query($mysqli, "SET NAMES 'utf8'");
}
// Check if album id is posted as GET parameter
$myq = $mysqli->query('SELECT * FROM Ages');
while ($myr = $myq->fetch_assoc()) {
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answer' => $myr['option1'],
'Answer' => $myr['option2'],
'Answer' => $myr['option3'],
'Answer' => $myr['option4'],
'CorrectAnswer' => $myr['CorrectAnswer'],
));
}
echo json_encode($array, JSON_UNESCAPED_UNICODE);
?>
output:
{
"Questions": [
{
"Question": "sfsa sfd s sdf",
"Answer": "vvv",
"CorrectAnswer": null
},
{
"Question": "dsfgdsfgv dsf dfs",
"Answer": "vvvv vv",
"CorrectAnswer": null
}
]
}
But I would like json output in below format: Answer are displayed multiple times for each question. Please suggest me what changes in my code.
{
"Questions": [
{
"Question": "dfsfdsfgv dfsfsd dfs sf",
"CorrectAnswer": 3,
"Answers": [
{
"Answer": "vvvvvvv"
},
{
"Answer": "vvv"
},
{
"Answer": "vv"
},
{
"Answer": "v"
}
]
},
{
"Question": "dgdsgdsgdsgszdfvgfvds",
"CorrectAnswer": 0,
"Answers": [
{
"Answer": "Lee"
},
{
"Answer": "Wrangler"
},
{
"Answer": "Levi's"
},
{
"Answer": "Diesel"
}
]
}
]
}
As pointed by jereon, you are overwriting the value of Answer key. You need to create a separate array for the all the Answers together.
Change
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answer' => $myr['option1'],
'Answer' => $myr['option2'],
'Answer' => $myr['option3'],
'Answer' => $myr['option4'],
'CorrectAnswer' => $myr['CorrectAnswer'],
));
to
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answers' => array((object)array('Answer' => $myr['option1']),
(object)array('Answer' => $myr['option2']),
(object)array('Answer' => $myr['option3']),
(object)array('Answer' => $myr['option4'])),
'CorrectAnswer' => $myr['CorrectAnswer'],
));
You should not assign multiple array elements with the same identifier ("Answer") as they would just overwrite each other. I would suggest you to use a non-associative array for the Answers so that your target JSON would look like this:
{
"Questions": [
{
"Question": "dfsfdsfgv dfsfsd dfs sf",
"CorrectAnswer": 3,
"Answers": [
"vvvvvvv",
"vvv",
"vv",
"v"
]
},
{
"Question": "dgdsgdsgdsgszdfvgfvds",
"CorrectAnswer": 0,
"Answers": [
"Lee",
"Wrangler",
"Levi's",
"Diesel"
]
}
]
}
Therefore you would use the following PHP code for the loop:
$array = array();
while ($myr = $myq->fetch_assoc()) {
$array["Questions"][] = array(
'Question' => $myr['Question'],
'CorrectAnswer' => $myr['CorrectAnswer'],
'Answers' => array(
$myr['option1'],
$myr['option2'],
$myr['option3'],
$myr['option4'],
),
);
}
First thing you are doing wrong is you are overwriting the value of answer options so what will happen is when your 1st option will be overwritten by 2nd option, 2nd option with 3rd and 3rd option with 4th option. So you will have to create an array for answers and push every answer in that array and in the end assign this answer option array to answer. So your code should look like below
while ( $myr = $myq->fetch_assoc () ) {
$answers_array=new array();
$answer_option=new stdClass(); // Create a object to format in required format and use this object to store every option of answer
$answer_option->answer=$myr['option1'];
array_push($answers_array,$answer_option);
$answer_option->answer=$myr['option2'];
array_push($answers_array, $answer_option);
$answer_option->answer=$myr['option3'];
array_push($answers_array, $answer_option);
$answer_option->answer=$myr['option4'];
array_push($answers_array,$answer_option);
$array["Questions"][] = array(
'Question' => $myr['Question'],
'CorrectAnswer' => $myr['CorrectAnswer'],
'answers' => $answers_array;
);
}

How do I remove nested object from an object in CakePHP?

CakePHP API returns result like this:
{
"status": "OK",
"themes": [
{
"Theme": {
"id": "20",
"user_id": "50",
"name": "dwdwdw",
"language_code_from": "cz",
"language_code_to": "en",
"type": "CUSTOM",
"created": "2014-10-19 15:36:05",
"count_of_cards": 0
}
}
]
}
I would like to ask, how can in remove nested Theme object to get result like this?:
{
"status": "OK",
"themes": [
{
"id": "20",
"user_id": "50",
"name": "dwdwdw",
"language_code_from": "cz",
"language_code_to": "en",
"type": "CUSTOM",
"created": "2014-10-19 15:36:05",
"count_of_cards": 0
}
]
}
Here is my CakePHP code:
$this->Theme->recursive = -1;
// GET USER ID
$themeData['user_id'] = $isSessionValid;
// GET ALL THEMES RELATED TO USER
$foundThemes = $this->Theme->find('all', array(
'conditions' => array(
'Theme.user_id' => $themeData['user_id'])
)
);
$themes = array();
// FOREACH THEMES AND GET COUNT FOR CARDS FOR EACH THEME
foreach($foundThemes as $foundTheme) {
// GET COUNT OF QUESTIONS FOR ACTUAL THEME
$countOfCards = $this->Theme->Card->find('count', array(
'conditions' => array(
'Card.theme_id' => $foundTheme['Theme']['id'])
)
);
// APPEND TO ACTUAL ARRAY
$foundTheme['Theme']['count_of_cards'] = $countOfCards;
array_push($themes,$foundTheme);
}
// SET SUCCESS RESPOSNSE
$this->set(array(
'status' => 'OK',
'themes' => $themes,
'_serialize' => array(
'status',
'themes',
)
));
Many thanks for any advice.
You can manipulate CakePHP's array formats using its built in Hash utility: http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash
What I would do would be to flatten the results:
$results = Hash::flatten($results);
Your data array will end up as a single dimensional array looking like this:
$results = array(
'status' => 'OK'
'themes.0.Theme.id' => 20,
...
'themes.1.Theme.id' => 21,
...
);
You can then use string replace to remove "Theme" from your keys:
$keys = array_keys($results);
$keys = str_replace('Theme.', '', $keys);
Then you can use Hash::expand to get your original array, now formatted how you want:
$results = Hash::expand(array_combine($keys, array_values($results)));
I dont think CakePHP supports this. if you want to do this with an easy way check the Set Utility.
http://book.cakephp.org/2.0/en/core-utility-libraries/set.html

Categories