John Davidson

php - Recursive traversal of nested objects and extract some properties

0 comments
Message:


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 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us