簡體   English   中英

遞歸遍歷嵌套對象並提取一些屬性

[英]Recursive traversal of nested objects and extract some properties

我正在努力應對以下情況:

我有一個 Category 類型的對象,它具有幾個私有屬性,我想通過其可用的 getter 將其提取到單獨的數據結構/數組中: getId()getTitle()getLink() 它也將任何嵌套的子類別存儲為屬性,可以通過 getter getSubCats()訪問該屬性,該屬性將返回一個關聯的類別數組,其中相應的 ID 作為鍵。

我需要提取一些屬性並創建一個嵌套數組(用於 json_encode),它符合以下結構:

<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(
      ...
    ),
    ...
  )
)

也許這可以通過使用 RecursiveIteratorIterator 來完成? 以下是我的最后兩種方法:

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;
}


提前感謝您的任何建議!

//編輯:

輸入結構(相關部分):

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;

}

一個具體的示例輸入對象可能如下所示:

$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'

期望的結果如下所示:

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(),
    )
  )
)

真實的對象樹有任意數量的分支和維度,但我認為這應該足以理解我想要做什么。

如您所見,所需的目標可以描述為“在過濾某些特定屬性的同時將對象轉換為數組”。 我希望這會讓事情更容易理解。

最后,我能夠自己解決這個問題。

僅對於存檔,以下代碼將執行該任務:

/**
 * Extracts all relevant properties of the given base category and all of its subcategories recursively
 * and assigns this data structure to the given template variable.
 *
 * @param Category $oCat    [mandatory] Target base category
 * @param array    $aOutput [optional]  Extraction storage
 * @param ?object  $oParent [internal]  Latest parent
 * @param bool     $return  [internal]  Return indicator
 *
 * @return array|void Derived category tree structure
 */
function buildTree($oCat, &$aOutput = [], $oParent = null, $return = true) {
  // scalar properties
  $aOutput[$actId]['id'] = $actId = $oCat->getId();
  $aOutput[$actId]['title'] = $oCat->getTitle();
  $aOutput[$actId]['url'] = $oCat->getLink();
  // parent property (object)
  if ( $oParent !== null ) {
    $aOutput[$actId]['parent'] = $oParent->getId();
  } elseif ( $parent = $oCat->getParentCategory() ) {
    $aOutput[$actId]['parent'] = $parent->getId();
  } else {
    $aOutput[$actId]['parent'] = ':globalroot'
  }
  // subcats property ([object])
  if ( $oCat->getHasVisibleSubCats() ) {
    foreach ( $oCat->getSubCats() as $sId => $oSubCat ) {
      $aOutput[$actId]['children'][$sId] = [
        'id'       => $sId,
        'title'    => $oSubCat->getTitle(),
        'url'      => $oSubCat->getLink(),
        'parent'   => $actId,
        'children' => null
      ];
      if ( $oSubCat->getHasVisibleSubCats() ) {
        foreach ( $oSubCat->getSubCats() as $oSubChild ) {
          buildTree($oSubChild, $aOutput[$actId]['children'][$sId]['children'], $oSubCat, false);
        }
      }
    }
  } else {
    $aOutput[$actId]['children'] = null;
  }
  if ( $return ) {
    return $aOutput;
  }
}

用法:

$aTree = buildTree($oBaseCat);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM