Düz tablodan hiyerarşik veri almak için PHP recursive function (Zend Framework)

4 Cevap php

Ben bir tablodan hiyerarşik veri almak için çalışıyorum ama bunu yapmak için başarısız duyuyorum. Ifc_key, ifc_name, ifc_parent: tablo (şimdilik) aşağıdaki sütunları vardır. ifc_key kullanılmaz. (Bu işlev için kullanılan birincil anahtar değil.

Amacı, bir dizi elde etmektir. Her eleman bir "ebeveyn" arayüzüdür. (Yani tüm bu kök elemanları ifc_parent seti (ayarlı ise ifc_name eşittir) yok ifc_name değerlerdir.

Aşağıdaki düzeni (demo) düşünün:

ifc_key | ifc_name | ifc_parent
0 | parent_ifc |
1 | a0a | parent_ifc
2 | a0b | parent_ifc
3 | b0a | vif1
4 | b0b | vif1
5 | vif1 | a0a

Yani sorgusu oluşturulan ben arıyorum dizidir:

Array
(
[parent_ifc] => Array
    (
        [a0a] => Array
            (
                [vif1] => Array
                    (
                        [0] => b0a
                        [1] => b0b
                    )

            )

        [a0b] => 
    )
)  

Ben ile geldi işlevi bu paragrafın altında olduğunu. Ben çocuk bulma üzerine kendisini çağırır ama sorun çocukların hiçbiri bu yöntemi ilk çağrısı üzerine seçilmiş olmasıdır tekrarlamalı bir fonksiyon, oluşturulan istedim. (Boş ebeveyn ile bu anne kendileri). (- Bu teoride belirsiz olabilir ve muhtemelen onların çocukları, vb) Yani sadece geri anne olsun, ama çocukların hiçbiri.

public static function getByFilerOrganisedChildren($filer_id, $parent = '')
{
    $table   = new Filer_Interface_Table();
    $where[] = $table->getAdapter()->quoteInto('ifc_system_id = ?', $filer_id);
    $where[] = $table->getAdapter()->quoteInto('ifc_parent = ?', $parent);
    $rows    = $table->fetchAll($where, 'ifc_parent ASC');

    foreach ($rows as $row) {
        if ($row->ifc_parent == '') $data[] = $row->ifc_name;
        else {
            $data[$row->ifc_parent][] = $row->ifc_name;
            self::getByFilerOrganisedChildren($filer_id, $row->ifc_parent);
        }
    }

    return (isset($data) ? $data : false);
}

4 Cevap

Sen bu yüzden bu soruya hemen uygun değil kabul edeceğiz senin yöntem önce ifc_system_id kolonuna hiçbir başvuru yaptı. Ayrıca olarak arzu belirttiğiniz çıkış aslında tutarsız.

Bu durumda, ifc_name yerine ifc_parent - sen kaçırıyorsun anahtar, öyle görünüyor ki, çocuğun kayıtları ile ilgili verileri kullanarak özyinelemeli işlev çağrısı için.

public function getByFilerOrganisedChildren($filer_id, $parent = '')
{
    $table   = new Filer_Interface_Table();
    $where[] = $table->getAdapter()->quoteInto('ifc_system_id = ?', $filer_id);
    $where[] = $table->getAdapter()->quoteInto('ifc_parent = ?', $parent);
    $rows    = $table->fetchAll($where, 'ifc_parent ASC');

    $data = array();
    foreach ($rows as $row) {
        $data[$row->ifc_name] = $this->getByFilerOrganisedChildren($row->ifc_name);
    }

    return (! empty($data) ? $data : false);
}

Ben burada soruyu cevaplarken, ama değilim: this is not very effective way to store hierarchical data in the database.

Ben oldukça iç içe Set (örn. Doktrini ORM ve Zend Framework [teklifin] kolay uygulamalar vardır) tavsiye ederim.

Ayrıca (Lehçe olduğu, ancak sağlanan SQL ve PHP örnekleri evrensel) this article açıklanan alternatif yöntemi deneyebilirsiniz.

public static function getByFilerOrganisedChildren($filer_id, $parent = '')
{
    $table   = new Filer_Interface_Table();
    $where[] = $table->getAdapter()->quoteInto('ifc_system_id = ?', $filer_id);
    $where[] = $table->getAdapter()->quoteInto('ifc_parent = ?', $parent);
    $rows    = $table->fetchAll($where, 'ifc_parent ASC');

    foreach ($rows as $row) {
        $data[$row->ifc_name] = array();
        /* self::getByFilerOrganisedChildren($filer_id, $row->ifc_name); */
    }

    Zend_Debug::dump($data);

    return (isset($this->data) ? $this->data : false);
}  

Yukarıdaki yorumladı hattı ile, Zend_Debug tarafından çıkış :: dökümü () 'dir:

array(7) {
["cifs-80"] => array(0) {
}
["e0M"] => array(0) {
}
["lo"] => array(0) {
}
["vif1"] => array(0) {
}
["vif1-81"] => array(0) {
}
["vif1-82"] => array(0) {
}
["vif1-83"] => array(0) {
}
}

Bunların hepsi "anne" dir. Ama beklendiği gibi (tabloya çağrı "ifc_parent =''" olduğu) çocuk (ve olası çocuk) hiçbiri döndürülür.

Ben uncomment Ancak ne zaman:

self::getByFilerOrganisedChildren($filer_id, $row->ifc_name);  

Çıktısı:

NULL  

Ben çünkü sanırım:

abstract class Filer_Interface_Abstract extends Filer_Db_Class  

Ama bu değiştirmek mümkün değilim - Geçerli uygulama nasıl inşa edildiğini beri. Önerileriniz?

Benim kod

DB şeması:

create table roles (
    id      int not null auto_increment,
    name    varchar(50) UNIQUE not null,
    inherit_id  int
)

PHP kodu:

class Default_Model_Roles extends Zend_Db_Table_Abstract {

   protected $_parents = array();

    public function getParents($id) {
        $this->_getAllParents($id);
        return (! empty($this->parents) ? $this->parents : FALSE);
    }

    public  function _getAllParents($id) {
        $select = $this->select();
        $select->where('id = ?', $id)
           ->order('id');
        $row = $this->fetchRow($select);
        $this->parents[] = $row->id;
        if ($row->inherit_id != NULL)   
            $this->_getAllParents($row->inherit_id);
    }
}

Kullanın:

$table = new Default_Model_Roles();
$parents = $table->getParents($this->role_id);