I am using a PHP Class that is generating a nested categories tree menu in json format from a MySQL database. The problem is that the array used to fill the data doesn't do what it is supposed to
The PHP Class is:
class nestedCategories {
public $json = array();
public function generateMenu($categories,$level){
$this->json = array();
foreach($categories as $category ){
$this->json['title'] = $category->description;
$this->json['expanded'] = true;
if(isset($category->children) && count($category->children)>0){
$this->json['folder'] = true;
$this->json['children'] = $this->generateMenu($category->children,$category->category_id);
} else {
$this->json['folder'] = false;
}
}
}
public function getJSON() {
return $this->json;
}
The $json is supposed to look like:
[
{"title": "Animalia", "expanded": true, "folder": true, "children": [
{"title": "Chordate", "folder": true, "children": [
{"title": "Mammal", "children": [
{"title": "Primate", "children": [
{"title": "Primate", "children": [
]},
{"title": "Carnivora", "children": [
]}
]},
{"title": "Carnivora", "children": [
{"title": "Felidae", "lazy": true}
]}
]}
]},
{"title": "Arthropoda", "expanded": true, "folder": true, "children": [
{"title": "Insect", "children": [
{"title": "Diptera", "lazy": true}
]}
]}
]}
]
but, when I am trying to pull the data from MySQL, the $json array only gives me the last pulled data from MySQL, as if it is erasing all data behind
Could someone talk me trough?
You are overwriting the array with each loop around categories, and wiping out the member variable with an array assignment each time round.
Plus, I suspect that it won't return the structure you're looking for unless you make it preoperly recursive (which means returning the array that you've built):
class nestedCategories {
public function generateMenu($categories,$level){
$categoriesJson = array();
foreach($categories as $category ){
$categoryJson = array();
$categoryJson['title'] = $category->description;
$categoryJson['expanded'] = true;
if(isset($category->children) && count($category->children)>0){
$categoryJson['folder'] = true;
$categoryJson['children'] = $this->generateMenu($category->children,$category->category_id);
} else {
$categoryJson['folder'] = false;
}
$categoriesJson[] = $categoryJson;
}
return $categoriesJson;
}
}
You would now just get back the data by calling generateMenu rather than using the member variable.
You are setting $this->json = array(); at the top of your generateMenu method. When you make the recursive call it destroys what was written to the array on the previous call.
In addition in each recursive call $this->json['title'] will over write the previous title. The same goes for expanded, children and folder.
It looks like I took a little longer that I should have to make the example code. Here it is anyway.
class Foo {
public function generateMenu($categories){
$json_array = array();
foreach($categories as $category) {
$json_object = array();
$json_object['title'] = $category->description;
if(isset($category->children) && count($category->children)>0){
// it looks like expanded should only be
// in objects with > 0 children
$json_object['expanded'] = true;
$json_object['folder'] = true;
$json_object['children'] = $this->generateMenu($category->children);
} else {
// based on the json in the question it looks like
// it should always contain a children array, but no folder element
$json_object['children'] = array();
}
$json_array[] = $json_object;
}
return $json_array;
}
}
Here is the test data:
$Diptera = new stdClass();
$Diptera->description = 'Diptera';
$Insect = new stdClass();
$Insect->description = 'Insect';
$Insect->children = array($Diptera);
$Arthropoda = new stdClass();
$Arthropoda->description = 'Arthropoda';
$Arthropoda->children = array($Insect);
$Felidae = new stdClass();
$Felidae->description = 'Felidae';
$Carnivora2 = new stdClass();
$Carnivora2->description = 'Carnivora';
$Carnivora2->children = array($Felidae);
$Carnivora = new stdClass();
$Carnivora->description = 'Carnivora';
$Primate2 = new stdClass();
$Primate2->description = 'Primate';
$Primate = new stdClass();
$Primate->description = 'Primate';
$Primate->children = array($Primate2, $Carnivora);
$Mammal = new stdClass();
$Mammal->description = 'Mammal';
$Mammal->children = array($Primate, $Carnivora2);
$Chordate = new stdClass();
$Chordate->description = 'Chordate';
$Chordate->children = array($Mammal);
$Animalia = new stdClass();
$Animalia->description = 'Animalia';
$Animalia->children = array($Chordate);
$catagories = array($Animalia);
Here is how it's called:
$f = new Foo();
echo json_encode($f->generateMenu($catagories), JSON_PRETTY_PRINT);
Here is the output:
[
{"title": "Animalia", "expanded": true, "folder": true, "children":
[
{"title": "Chordate", "expanded": true, "folder": true, "children":
[
{"title": "Mammal", "expanded": true, "folder": true, "children":
[
{"title": "Primate", "expanded": true, "folder": true, "children":
[
{"title": "Primate", "children": []},
{"title": "Carnivora", "children": []}
]
},
{"title": "Carnivora", "expanded": true, "folder": true, "children":
[
{"title": "Felidae", "children": []}
]
}
]
}
]
},
{"title": "Arthropoda", "expanded": true, "folder": true, "children":
[
{"title": "Insect", "expanded": true, "folder": true, "children":
[
{"title": "Diptera", "children": []}
]
}
]
}
]
}
]
You are overwriting the array keys when you iterate over the JSON.
$array = array();
$array['foo'] = 'bar';
//$array['foo] = 'bar';
$array['foo'] = 'foo';
//$array['foo'] = 'foo';
Related
In a Symfony project, I have a user-contacts.json file which contains :
[
{
"id": 137,
"userName": "testUserName",
"userEmail": "test#email.com",
"userQuestion": "This is my question ?",
"solved": false
}
]
In a service, I'm receiving an object coming from a symfony form, here is the content:
ContactFile.php on line 18:
App\Entity\Contact {#561 ▼
-id: 146
-userName: "Contact"
-userEmail: "test#test.com"
-userQuestion: "test ?"
-solved: false
}
I'd like to append this contact query to the user-contacts.json file, in a way that the user-contacts.json content has a valid JSON format, like so for example:
[
{
"id": 137,
"userName": "testUserName",
"userEmail": "test#email.com",
"userQuestion": "This is my question ?",
"solved": false
},
{
"id": 138,
"userName": "anotherUserName",
"userEmail": "another#email.com",
"userQuestion": "This is another question ?",
"solved": false
}
]
Unfortunately, here is my result right now:
[
[
{
"id": 148,
"userName": "anotherUserName",
"userEmail": "another#email.com",
"userQuestion": "Another question?",
"solved": false
}
],
{
"id": 149,
"userName": "test",
"userEmail": "test#test.com",
"userQuestion": "Question ?",
"solved": false
}
]
Here is my service code:
<?php
namespace App\Service;
use App\Entity\Contact;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Serializer\SerializerInterface;
class ContactFile
{
public function __construct(private Filesystem $filesystem, private SerializerInterface $serializer) {}
public function writeContactFile(Contact $contact): void
{
$actualFileContent = file_get_contents('../user-contacts/user-contacts.json');
$requestContent = $this->serializer->serialize($contact, 'json');
$array[] = json_decode($actualFileContent, true);
$array[] = json_decode($requestContent, true);
$result = json_encode($array, JSON_PRETTY_PRINT);
$this->filesystem->remove(['file', '../user-contacts/', 'user-contacts.json']);
$this->filesystem->appendToFile('../user-contacts/user-contacts.json', $result);
}
}
How would you append this "Contact" object to the user-contacts.json file, while having a standard JSON format?
As Cbroe said:
I replaced $array[] = json_decode($actualFileContent, true); to $array = $actualFileContent;
And now it's working. Thank you.
I have some struggles how to map infinite object in Laravel.
So I have one table Categories that I'm getting in controller like:
$find_parent = Category::where('slug', $slug)->with('childrenRecursive')->first();
childrenRecursive() works fine in that case.
And return of this object would be like (minified):
{
"id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"parent_id": "f0d29100-d2bc-48c8-89cf-985e0c03b8ac",
"children_recursive": [
{
"id": "30bf23a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"children_recursive": [
{
"id": "32312a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "30bf23a7-b28c-4s78-b873-1df589eebcb1",
}
]
},
{
"id": "32bf23a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"children_recursive": []
}
]
}
So from this, I have to get all id's in every object. So I have foreach function in controller that looks like:
$find_parent = Category::where('slug', $slug)->with('childrenRecursive')->first();
$array = [];
foreach($find_parent->childrenRecursive as $l){
array_push($array, $l->id);
if($l->childrenRecursive){
$result = array_merge($array, $this->catTree($l->childrenRecursive));
}
}
return $result;
And catTree would look like:
public function catTree($list){
$tree = [];
foreach($list as $l){
array_push($tree, $l->id);
if($l->childrenRecursive){
array_merge($tree, $this->catTree($l->childrenRecursive));
}
}
return $tree;
}
So this is returning some of the objects, but not everything. What am I doing wrong here?
I have the following which I would like to order alphabetically by the Key i.e first for each array group would be "bname", followed by "created_at".
{
"leads": [
{
"lead_id": 1,
"zoho_lead": null,
"bname": "ABC Limited",
"tname": "ABC",
"source_id": 11,
"industry_id": 1,
"user_id": 1,
"created_at": "2017-09-06 15:54:21",
"updated_at": "2017-09-06 15:54:21",
"user": "Sean McCabe",
"source": "Unknown",
"industry": "None"
},
{
"lead_id": 2,
"zoho_lead": 51186111981,
"bname": "Business Name Limited",
"tname": "Trading Name",
"source_id": 11,
"industry_id": 1,
"user_id": 1,
"created_at": "2017-06-01 12:34:56",
"updated_at": null,
"user": "John Doe",
"source": "Unknown",
"industry": "None"
}
]
}
I'm trying to use ksort like so in the foreach loop:
class LeadController extends Controller
{
use Helpers;
public function index(Lead $leads)
{
$leads = $leads->all();
foreach($leads as $key => $lead){
$lead->user = User::where('id', $lead->user_id)->first()->name;
$lead->source = Source::where('id', $lead->source_id)->first()->name;
$lead->industry = Industry::where('id', $lead->industry_id)->first()->name;
$lead->ksort();
}
return $leads;
}
But I get the following error:
Call to undefined method Illuminate\\Database\\Query\\Builder::ksort()
How do I use this function, or is there a Laravel way of doing this, or a better way altogether?
Thanks.
Managed to get it to return with the Keys in alphabetical order, so below is the solution in-case someone else should require it:
public function index(Lead $leads)
{
$leadOut = Array();
$leads = $leads->all();
foreach($leads as $key => $lead){
$lead->user = User::where('id', $lead->user_id)->first()->name;
$lead->source = Source::where('id', $lead->source_id)->first()->name;
$lead->industry = Industry::where('id', $lead->industry_id)->first()->name;
//Convert to Array
$leadOrder = $lead->toArray();
//Sort as desired
ksort($leadOrder);
//Add to array
$leadOut[] = $leadOrder;
}
return $leadOut;
}
There is likely a cleaner way to do this, but it works for my instance, and perhaps additional answers may be posted that are better.
You could do something like:
return Lead::with('user', 'source', 'industry')->get()->map(function ($lead) {
$item = $lead->toArray();
$item['user'] = $lead->user->name;
$item['source'] = $lead->source->name;
$item['industry'] = $lead->industry->name;
ksort($item);
return $item;
});
This should be much more efficient as it will eager load the relationships rather than make 3 extra queries for each iteration.
I want to remove Extra array from this JSON "data".
how to do this in PHP. Is it any function in PHP that solve it.?
{
"data": [
[
{
"user_id": "654120",
"user_name": "Jhon_Thomsona",
"user_image": null
}
],
[
{
"user_id": "1065040766943114",
"user_name": "Er Ayush_Gemini",
"user_image": "KP8LSHQFwk.png"
}
]
]
}
I want my final array to look like this:
{
"data": [
{
"user_id": "654120",
"user_name": "Jhon_Thomsona",
"user_image": null
},
{
"user_id": "1065040766943114",
"user_name": "Er Ayush_Gemini",
"user_image": "KP8LSHQFwk.png"
}
]
}
You can remove the extra array layer around each user object by mapping reset over the elements of data, then reencoding as JSON.
$data = json_decode($json);
$data->data = array_map('reset', $data->data);
$json = json_encode($data);
Of course, if you are creating this JSON yourself, you should avoid creating this structure to begin with rather than altering it after the fact.
<?php
$foo = json_decode($yourjson);
$data = [];
foreach($foo->data as $array) $data = array_merge($data, $array);
$foo->data = $data;
$yourjson = json_encode($foo);
EDIT Use of array_merge + Oriented object
Hi friends i'm getting json from server (using kohana framework 3.0) like this....
{
"aaData": [
{
"regNo": "1",
"regDate": "2025-05-12",
"patientName": "Ratna",
"address": "saasgasgasga",
"city": "Hyderabad",
"phno": "2147483647",
"mrgStatus": "single",
"religion": "1",
"gender": "male",
"fathername": "Yohan",
"status": "2",
"age": "25"
}
]
}
but i want below format
{
"aaData": [
[
"1",
"2025-05-12",
"Ratna",
"saasgasgasga",
"Hyderabad",
"2147483647",
"single",
"1",
"male",
"Yohan",
"2",
"25"
]
]
}
kohana controller is
public function action_index()
{
$table = new Model_patientdetails();
$log =$table ->get_all();
$output = array("aaData" => $log);
$this->auto_render=false;
echo json_encode($output);
}
please suggest me how to get required json format
Thanks in advance
Use array_values() for get the values only
public function action_index()
{
$table = new Model_patientdetails();
$log =$tab ->get_all();
foreach($log as &$l)
{
$l = array_values($l)
}
$output = array("aaData" => $log);
$this->auto_render=false;
echo json_encode($output);
}
I haven't found $log1 variable at your code, so I think it was $log.
You can do it in this way:
public function action_index()
{
$table = new Model_patientdetails();
$log = $tab->get_all();
$output = array("aaData" => array_values($log));
$this->auto_render=false;
echo json_encode($output);
}