I'm struggling with the following situation:
I have an object of type Category with several private properties I want to extract into a separate data structure / array through its available getters: getId(), getTitle(), getLink(),.
It stores any nested subcategories as a property as well, which can be accessed through getter getSubCats() which will return an associative array of Categories with the corresponding ID's as keys.
I need to extract some properties and create a nested array (for use with json_encode) which fits the following structure:
<ID> => array(
'title' => <title>,
'url' => <url>,
'parent' => <parentID>,
'children' => array(
<ID> => array(
'title' => <title>,
'url' => <url>,
'parent' => <parentID>,
'children' => array(
...
),
<ID> => array(
'title' => <title>,
'url' => <url>,
'parent' => <parentID>,
'children' => array(
...
),
...
)
)
Maybe this can be done by using RecursiveIteratorIterator?
Below are my last two approaches:
function buildTree_v1(&$oCat, &$aOutput = [], &$oParent = null) {
$actId = $oCat->getId();
$aOutput [$actId]['title'] = $oCat->getTitle();
$aOutput [$actId]['url'] = $oCat->getLink();
$aOutput [$actId]['parent'] = $oCat->getParentCategory()->getId() ?? null;
if ( $oCat->getHasVisibleSubCats() ) {
foreach ( $oCat->getSubCats() as $sId => &$oSubCat ) {
$aOutput [$actId][$sId] = [];
foreach ( $oSubCat as &$oSubChild ) {
buildTree_v1($oCat, $aOutput, $oSubChild);
}
}
}
}
// Try to split - only build the nested object structure as first step
function buildTree_v2(&$oCat) {
$return = [];
if ( $oCat->getHasVisibleSubCats() ) {
foreach ( $oCat->getSubCats() as &$oSubCat) {
if ( $oSubCat->getHasVisibleSubCats() ) {
$return[$oSubCat->getId()] = buildTree_v2($oSubCat);
} else {
$return[] = $oSubCat->getId();
}
}
}
return empty($return) ? null : $return;
}
Thanks in advance for any advice!
//Edit:
Input structure (relevant parts):
class Category {
protected $_aSubCats = array();
protected $_blHasVisibleSubCats;
protected $_aSeoUrls = array();
protected $_oParent = null;
protected $_sId;
protected $_sTitle;
public function getSubCats(): array<Category>;
public function getHasVisibleSubCats(): bool;
public function getLink($iLang = null): string;
public function getParentCategory(): ?Category;
public function getId(): string;
public function getTitle(): string;
}
An concrete example input object might look like:
$oInputCat = {Category}
-> $_aSubCats = array(
'316' => {Category},
'23' => {Category},
'262' => {Category}
)
-> $_blHasVisibleSubCats = true
-> $_aSeoUrl = 'https://example.com/Hardware'
-> $_oParent = {Category}
-> $_sId = '5068'
-> $_sTitle = 'Hardware'
/* Entries of $_aSubCats */
// '316' = {Category}
-> $_aSubCats = array()
-> $_blHasVisibleSubCats = false
-> $_aSeoUrl = 'https://example.com/Hardware/3D-Googles'
-> $_oParent = {Category}
-> $_sId = '316'
-> $_sTitle = '3D Googles'
// '23' = {Category}
-> $_aSubCats = array(
'26' => {Category}
)
-> $_blHasVisibleSubCats = true
-> $_aSeoUrl = 'https://example.com/Hardware/CPUs-and-Cooler'
-> $_oParent = {Category}
-> $_sId = '23'
-> $_sTitle = 'CPUs & Cooler'
// '262' = {Category}
-> $_aSubCats = array()
-> $_blHasVisibleSubCats = false
-> $_aSeoUrl = 'https://example.com/Hardware/Sound-Cards'
-> $_oParent = {Category}
-> $_sId = '262'
-> $_sTitle = 'Sound Cards'
// '26' = {Category} <-- example for a 2nd level subcategory
-> $_aSubCats = array()
-> $_blHasVisibleSubCats = false
-> $_aSeoUrl = 'https://example.com/Hardware/CPUs-and-Cooler/Cooler'
-> $_oParent = {Category}
-> $_sId = '26'
-> $_sTitle = 'Cooler'
The desired result would look like:
array(
'5068' => array(
'title' => 'Hardware',
'url' => 'https://example.com/Hardware',
'parent' => '12', // not listed - parent of the input category
'children' => array(
'316' => array(
'title' => '3D Googles',
'url' => 'https://example.com/Hardware/3D-Googles',
'parent' => '5068',
'children' => array(),
'23' => array(
'title' => 'CPUs & Cooler',
'url' => 'https://example.com/Hardware/CPUs-and-Cooler',
'parent' => '5068',
'children' => array(
'26' => array(
'title' => 'Cooler',
'url' => 'https://example.com/Hardware/CPUs-and-Cooler/Cooler',
'parent' => '23',
'children' => array(),
),
'262' => array(
'title' => 'Sound Cards',
'url' => 'https://example.com/Hardware/Sound-Cards',
'parent' => '5068',
'children' => array(),
)
)
)
The real object tree has an arbitrary number of branches and dimensions, but I think this should be enough to understand, what I want to do.
As you can see, the desired target could be described as "convert the objects to arrays while filtering some specific properties".
I hope this will make things easier to understand.
My Answer:
You can achieve the desired result by recursively traversing the nested Category objects and extracting the required properties. Here's an updated version of your code that should work:
php
function buildTree($oCat) {
$output = [];
$output[$oCat->getId()] = [
'title' => $oCat->getTitle(),
'url' => $oCat->getLink(),
'parent' => $oCat->getParentCategory() ? $oCat->getParentCategory()->getId() : null,
'children' => []
];
if ($oCat->getHasVisibleSubCats()) {
foreach ($oCat->getSubCats() as $subCat) {
$output[$oCat->getId()]['children'][$subCat->getId()] = buildTree($subCat);
}
}
return $output;
}
// Example usage
$oInputCat = new Category(); // Assuming you have instantiated the Category object
$result = buildTree($oInputCat);
// Convert the result to JSON
$jsonResult = json_encode($result);
echo $jsonResult;
In this code snippet, the `buildTree` function recursively traverses the nested Category objects and builds the desired nested array structure. The function returns the nested array, which can then be converted to JSON using `json_encode`.
Make sure to replace `Category` with the actual class name of your Category object in the code above. Also, ensure that the getters (`getId()`, `getTitle()`, `getLink()`, `getSubCats()`, `getHasVisibleSubCats()`, `getParentCategory()`) return the correct values as per your object structure.
I hope this helps! Let me know if you have any further questions.
Rate this post
4 of 5 based on 5859 votesComments