Iki tablo ile yakınlık Listesi Model

1 Cevap php

Yani think Benim sorun iki soru için aşağı kaynar:

  1. Ağaç akılda performansı tutarken komşuluk Listesi Model yaklaşımı kullanarak (iki tablo arasında) MySQL saklanan olduğunda PHP nasıl bir çaprazlanabiliyorsa ağaç yapısı yaratırım?

  2. Kastetmek kod çoğaltma ve if / else ve switch deyimleri ile mantığı çöp olmadan gerekli biçimlerde görüntüleniyor ağaç için bir sürdürülebilir yaklaşım nedir?

Aşağıda detaylar:

Ben Zend Framework kullanıyorum.

Ben bir anket ile çalışıyorum. Soru ve question_groups: Bu iki ayrı tablo arasında bir MySQL veritabanında saklanır. Her tablo uygun Zend_Db_Table_ * sınıfları uzanır. Hiyerarşi komşuluk Listesi Model yaklaşımı kullanılarak temsil edilir.

Ben çalıştırıyorum sorunlar nedeniyle yüzden ben alternatiflere açığım bir RDBMS bir ağaç yapısı doldurma olduğumu aslında muhtemeldir biliyoruz. Ancak, ben de anket cevaplayıcıları ve yanıtları saklamak ediyorum bu yüzden alternatif yaklaşımlar olduğunu desteklemek gerekir.

Anket çeşitli HTML formatlarında görünecek gerekiyor:

  1. (Zend_Form kullanarak) yanıtları girmek için bir form olarak
  2. Bağlantılar soru ya da grup tarafından yanıtları görmek için gibi sorulara (ve some grupları) ile (iç içe) sıralı bir liste olarak.
  3. Her soru eklenen tepkiler ile (iç içe) sıralı bir liste olarak.

Sorular yaprak düğümlerin ve question_groups diğer question_groups ve / veya soruları içerebilir. Kombine, bir işlemek için 100 satır üzerinde küçük ve ekran vardır.

Şu anda, bir question_group çocuklarını almak için özyineleme kullanarak tüm işlemleri yapar bir görünüm yardımcınız var (iki tablo arasında bir UNION gerçekleştiren bir sorgu: QuestionGroup :: getChildren ($ id)). Soru yanıt ile anket görüntülerken artı iki sorgu davalı ve her soruya verdikleri yanıt almak için gereklidir.

Sayfa yükleme süresi olmasa da çok uzun bu yaklaşım yanlış geliyor. Özyineleme artı hemen hemen her düğüm için birden fazla veritabanı sorguları içimde çok sıcak ve bulanık hissediyorum yapmaz.

Ben denedim recursion-less ve tam ağaç dizide özyinelemeli yöntemleri hiyerarşik bir geçiş için dizi ve ekran oluşturmak için BİRLİĞİ döndü. Ancak, bu nedeniyle grupları ve soruları ayrı ayrı tablolarda saklanır aslında düğüm kimlikleri var çoğaltılır beri yıkmak gibi görünüyor. Belki orada bir şey eksik ...

Şu anda, yukarıda listelenen biçimlerde ağacı görüntülemek için mantık oldukça karmaşa. Ben her yerde kastetmek mantığı çoğaltmak için tercih ediyorum. Ancak, her yerde koşul ya en kolay sıçramalı kodu üretemezler. Ben, ziyaretçileri dekoratörler ve PHP SPL Yineleyicilerde bazı kadar okudum ama ben hala nasıl bu olur birlikte Zend_Db_Table, Zend_Db_Table_Rowset ve Zend_Db_Table_Row uzanan sınıfları ile tüm iş. Belirsiz hissediyorum Ben veritabanından hiyerarşisini binanın önceki sorunu çözülmüş değil, özellikle bu yana. Bu biraz kolayca yeni görüntü biçimleri ekleyebilir (ya da mevcut olanları değiştirmek) güzel olurdu.

1 Cevap

  • Komşuluk Listesi geleneksel size onun hemen üst bir satır bağlanan her satırda bir parent_id sütunu verir. Satır bir ağacın kökü ise parent_id NULL. Ama bu pahalı birçok SQL sorguları çalıştırmak yol açar.

  • Başka bir sütun root_id ekle böylece her satır kendisine ait ne ağaç bilir. Bu şekilde tek bir SQL sorgusu ile verilen bir ağacın tüm düğümleri getirebilir. Ağacın kök kimliği ile Rowset almak için Table sınıfına bir yöntem ekleyin.

    class QuestionGroups extends Zend_Db_Table_Abstract
    {
        protected $_rowClass = 'QuestionGroup';
        protected $_rowsetClass = 'QuestionGroupSet';
        protected function fetchTreeByRootId($root_id)
        {
             $rowset = $this->fetchAll($this
                ->select()
                ->where('root_id = ?', $root_id)
                ->order('id');
            );
            $rowset->initTree();
            return $rowset;
        }
    }
    
  • Zend_Db_Table_Row ve verilen satırın üst almak ve aynı zamanda bir Rowset kendi çocuklarının fonksiyonları yazmalıyız uzanan özel bir sınıf yazın. Row sınıf ebeveyn ve çocukların dizi başvurmak için korumalı veri nesneleri içermelidir. A Row nesne aynı zamanda bir getLevel() fonksiyonu ve bir izleme nesneleri için getAncestorsRowset() fonksiyonu olabilir.

    class QuestionGroup extends Zend_Db_Table_Row_Abstract
    {
        protected $_children = array();
        protected $_parent   = null;
        protected $_level    = null;
        public function setParent(Zend_Db_Table_Row_Abstract $parent)
        {
            $this->_parent = $parent;
        }
        public function getParent()
        {
            return $this->_parent;
        }
        public function addChild(Zend_Db_Table_Row_Abstract $child)
        {
            $this->_children[] = $child;
        }
        public function getChildren()
        {
            return $this->_children;
        }
        public function getLevel() {}
        public function getAncestors() {}
    }
    
  • Eğer bir ağaç olarak hareket böylece ebeveyn ve çocuklar referanslar ayarı, satır kümesi satırlar üzerinde yineleme için bir işlevi vardır Zend_Db_Table_Rowset uzanan özel bir sınıf yazın. Ayrıca Rowset, bir getRootRow() işleve sahip olmalıdır.

    class QuestionGroupSet extends Zend_Db_Table_Rowset_Abstract
    {
        protected $_root = null;
        protected function getRootRow()
        {
            return $this->_root;
        }
        public function initTree()
        {
            $rows = array();
            $children = array();
            foreach ($this as $row) {
              $rows[$row->id] = $row;
              if ($row->parent_id) {
                $row->setParent($rows[$row->parent_id]);
                $rows[$row->parent_id]->addChild($row);
              } else {
                $this->_root = $row;
              }
            }
        }
    }
    

Şimdi bir satır kümesi getRootRow() çağırabilir, ve kök düğümü döndürür. Eğer kök düğümünü var sonra, getChildren() çağırır ve onlar üzerinde döngü olabilir. Sonra bu ara çocukların herhangi bir zamanda getChildren() çağırabilir ve istediğiniz herhangi bir biçimde bir ağaç özyinelemeli çıktı.