【问题标题】:Generating tree from database in Yii在 Yii 中从数据库生成树
【发布时间】:2013-09-15 17:43:12
【问题描述】:

我在 Yii 中有一个模型,它代表一棵树,并带有以下 MySQL 表:

CREATE TABLE IF NOT EXISTS `nodes` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `node` varchar(255) NOT NULL,
    [ something more not necessary to display here ]
    `parentid` int(11) NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
) ENGINE=InnoDB;

我对这个模型有以下关系:

return array(
    'parentnode'=>array(self::BELONGS_TO, 'Nodes', 'parentid'),
    'childnode'=>array(self::HAS_MANY, 'Nodes', 'parentid'),
);

我正在使用 CTreeView 来显示树。使用 $model->childnode 递归地迭代所有 parentid=0 的节点来构建源数组。这是迭代函数:

public static function nodetree($params) { //finds all top-level nodes
    $retval=array();
    $nodes=Nodes::model()->findAllByAttributes(array('parentid'=>0));
    foreach($nodes as $anode)
        $retval[]=Nodes::nodearray($anode, $params);
}

这是递归函数。

public static function nodearray($_node, $params) { // finds children
    $retval=array(
        'text'=>$_node->node, //may differ based on options
        'id'=>$_node->id,
        'expanded'=>false,    //may differ based on options
        'children'=>array(),
    );
    foreach ($_node->childnode as $c_node)
        $retval['children'][]=Nodes::nodearray($c_node, $params);
    return $retval;
}

由于 Yii 的开销,这可能不是最快的方法。在没有其他应用程序运行的开发服务器上生成页面需要 1 秒以上。节点超过 1K,并在需要时由用户更新。

如何更快地生成树/页面?

【问题讨论】:

    标签: php yii


    【解决方案1】:

    嗯,很遗憾我回答了自己的问题,但不知何故我找到了解决方案。

    我创建了一个缓存表:

    CREATE TABLE IF NOT EXISTS `treecache` (
        `param` varchar(255) NOT NULL,
        `cachedtree` mediumtext NOT NULL,
        PRIMARY KEY (`param`)
    ) ENGINE=InnoDB;
    

    我修改了nodetree函数如下:

    public static function nodetree($param) { //finds all top-level nodes
        $paramstr = serialize($param);
        if (strlen($paramstr)<256) {
            $oval=Yii::app()->db->createCommand('SELECT cachedtree FROM treecache WHERE param=:param')->queryRow(true, array('param'=>$paramstr));
            if (isset($oval['cachedtree'])) return unserialize($oval['cachedtree']);                    
        }
        $retval=array();
        $nodes=Nodes::model()->findAllByAttributes(array('parentid'=>0));
        foreach($nodes as $anode)
            $retval[]=Nodes::nodearray($anode, $param);
        if (strlen($paramstr)<256)
            Yii::app()->db->createCommand('INSERT INTO treecache VALUES (:param, :cachedtree)')->execute(array('param'=>$paramstr, 'cachedtree'=>serialize($retval)));
        return $retval;
    }
    

    此外,为了应对节点的变化,我在我的模型中添加了一个新功能:

    public function afterSave() {
        Yii::app()->db->createCommand('TRUNCATE treecache')->execute();
        return parent::afterSave();
    }
    

    这不会加速树的生成过程,但会根据参数缓存生成的树,并比迭代/递归更快地返回结果。我仍然对任何 cmets 持开放态度...

    【讨论】:

      【解决方案2】:

      这是迄今为止我测试过的最有效的方法。源自http://blog.ideashower.com/post/15147134343/create-a-parent-child-array-structure-in-one-pass

      public static function nodetree($param=array()) {
          $refs = array();
          $list = array();
      
          $nodes = Yii::app()->db->createCommand('select * from nodes')->queryAll();
      
          foreach ($nodes as $data) {
              $thisref = &$refs[ $data['id'] ];
              $thisref['parentid'] = $data['parentid'];
              $thisref['text'] = $data['node'];
              if ($data['parentid'] == 0) {
                  $list[ $data['id'] ] = &$thisref;
              } else {
                  $refs[ $data['parentid'] ]['children'][ $data['id'] ] = &$thisref;
              }   
          }           
          return $list;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 2012-12-06
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多