dedecms核心类源码分析

dedecms核心类源码分析

   最近公司一个cms类型的项目,时间紧任务重。经过快速的决策后,选择了dedecms开发1.0版本,满足基本需求。以前从来没有接触过这个系统,而且此系统文档是相当的不全。所以分析源代码是最好的方式。学习一个系统,首要的是搞懂它的数据引擎、模板引擎。dedetag.class.php 这个文件就是核心底层模板解析引擎,其它的引擎都是在这个基础上增加了自己的函数而已。

一、dedetag.class.php

 1.DedeTag :最后存储的CTags的结构类,提供一些读取CTags属性的方法。(这个很重要)
    2.DedeAttribute : 最后存储的CTags->attr 的属性结构类(count,Items)
    3.DedeAttributeParse: 属性解析器,解析提供属性结构到CTags变量。
    4.DedeTagParse核心解析器      

 1        1.LoadTemplate 载入模板。
 2             1. while($line = fgets($fp,1024)) //line 379循环读取文件赋值到变量 $this->SourceString .= $line;
 3             2. if($this->LoadCache($filename))//line 384在有缓存的情况,读取缓存文件到 CTags
 4             3.  $this->ParseTemplet();//line 390 没有缓存则调用模板解析方法
 5         2.ParseTemplet 解析模板
 6             1.循环遍历,按正则匹配每个标签的位子和属性,并保存到 CTags
 7             2. $this->SaveCache(); //line 952 ,如果开启缓存配置则保存到缓存文件
 8         3.GetResult 输出模板
 9             1. $this->AssignSysTag();// line 738 处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)      
10         4.AssignSysTag  处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)
11         5.Assign         封装模板的类(arclist/channel/memeberlist.....)和字段的解析是channelunit.helper.php中MakeOneTag函数在处理,
12             $dtp->Assign($tagid,$funcname($ctag,$refObj)); // line 558 调动地底层模板解析引擎的赋值函数为便签赋值。            

二、arc.partview.class.php 分析

 1     index.php调用arc.partview.class.php
 2     1.$this->dtp = new DedeTagParse();//line 47 初始化底层模板解析引擎
 3     2.$this->SetTemplet();//line 134 读取要解析的模板 
 4     3.$this->dtp->LoadTemplet($temp); //line 142 实际调用的是底层模板解析引擎 
 5     4.$this->ParseTemplet(); //line 149 封装的解析模板方法
 6     5.MakeOneTag($this->dtp,$this); //line 224 这个函数放在 channelunit.func.php 文件中,
 7     6.helper('channelunit');// line 29 调用helper工具加载对应的函数。channelunit.helper.php
 8     7.if($tagname=='field' && $parfield=='Y') //line 515 解析field 模板
 9     8.$funcname = 'lib_'.$tagname; //line 557 加载对应的封装模板的类(arclist/channel/memeberlist.....)
10     9.$dtp->Assign($tagid,$funcname($ctag,$refObj)); // line 558 调动地底层模板解析引擎的赋值函数为便签赋值。
11    10.$this->$dtp->EvalFunc($fieldvalue,$functionname,&$refObj); //line 965 动地底层模板解析引擎处理某字段的函数(模板中直接使用函数最终也是调用的此方法加载对应的函数返回值)
12    11.$this->dtp->GetResult();//line 169 调动地底层模板解析引擎的输出方法
13    12.$this->dtp->AssignSysTag(); //line 738  调动地底层模板解析引擎处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)
14    13.$this->dtp->CTags[$i]->TagValue = $str; 每一次解析模板赋值都会修改CTags的TagValue
15    
16    总结:封面模板解析类是对 dedetag.class.php 的封装。加入了一些自己的处理逻辑

三、写自己的模板解析

      

    
  1 <?php 
  2 require_once(dirname(__FILE__)."/../include/common.inc.php");
  3 require_once(DEDEINC.'/channelunit.class.php');
  4 require_once(DEDEINC.'/typelink.class.php');
  5 require_once(DEDEINC.'/ftp.class.php');
  6 /**
  7  * 模板调用事例
  8  *
  9  * @version        2018-11-01
 10  * @package        1.0.1
 11  * @author         main_wu
 12  */
 13 class TestView
 14 {
 15     public $dsql;
 16     public $dtp;
 17     public $TypeID;
 18     public $Fields;
 19     public $TypeLink;
 20     public $pvCopy;
 21     public $refObj;
 22     public $ftp;
 23     public $remoteDir;
 24 
 25     public function __construct($typeid=0, $needtypelink=true)
 26     {
 27         global $_sys_globals,$ftp;
 28         $this->TypeID = $typeid;
 29         $this->dsql = $GLOBALS['dsql'];
 30         $this->dtp = new DedeTagParse();
 31         $this->dtp->SetNameSpace("dede", "{", "}");
 32         $this->dtp->SetRefObj($this);
 33         $this->ftp = &$ftp;
 34         $this->remoteDir = '';
 35         //加载模板->解析模板
 36         $this->dtp->LoadTemplet(DEDETEMPLATE ."/default/test.htm");
 37 
 38         //字段,通过{dede:filed.myname}访问到。在display时,由$this->dtp->AssignSysTag()处理
 39         //如果需要面包屑导航等信息,则要new TypeLink,原理也是往Fields中在赋值
 40         if ($needtypelink) {
 41             $this->TypeLink = new TypeLink($typeid);
 42             if (is_array($this->TypeLink->TypeInfos)) {
 43                 foreach ($this->TypeLink->TypeInfos as $k=>$v) {
 44                     if (preg_match("/[^0-9]/", $k)) {
 45                         $this->Fields[$k] = $v;
 46                     }
 47                 }
 48             }
 49             $_sys_globals['curfile'] = 'partview';
 50             $_sys_globals['typename'] = $this->Fields['typename'];
 51 
 52             //设置环境变量
 53             SetSysEnv($this->TypeID, $this->Fields['typename'], 0, '', 'partview');
 54             $this->Fields['position'] = $this->TypeLink->GetPositionLink(true);
 55             $this->Fields['title'] = $this->TypeLink->GetPositionLink(false);
 56         }
 57         $this->Fields['myname']="mian_wu";
 58         //全局变量,可以通过{dede:globel.testlist}访问到。在display时,由$this->dtp->AssignSysTag()处理
 59         $GLOBALS['testlist']=array(1,2,3,4,5);
 60        
 61 
 62         //解析框架自定义模板,arclist/channel/memeberlist.....
 63         MakeOneTag($this->dtp, $this);
 64         //解析自己定义模板,沒有自定义则此代码不需要。
 65         foreach ($this->dtp->CTags as $tid => $ctag) {
 66             if ($ctag->GetName()=="myfield") {
 67                 //自定义单标签
 68                 //$this->assgin() //去解析自定义模板
 69                 $this->dtp->Assign($tid, $this->Fields[$ctag->GetAtt('name')]);
 70             } elseif ($ctag->GetName()=="mytag") {
 71                 //自定义复合标签
 72                 //自定义模板解析的两种方式
 73                 //1.可以写在taglib/tagName.lib.php的形式,模板会自动加载并解析。
 74                 //2.直接在CTags里面通过名字匹配到id,并assin进入值。
 75                 $this->dtp->Assign($tid, $this->Mytag($ctag->GetInnerText()));
 76             }
 77         }
 78     }
 79     public function Mytag($innertext)
 80     {
 81         //重新初始化底层解析模板。
 82         $dtp2 = new DedeTagParse();
 83         $dtp2->SetNameSpace('field', '[', ']');
 84         $dtp2->LoadSource($innertext);
 85         foreach ($dtp2->CTags as $k=>$ctag) {
 86             if ($ctag->GetName()=='myname') {
 87                 //此处赋的值,自行处理
 88                 $dtp2->Assign($k, "mian_wu");
 89             }
 90         }
 91         return $dtp2->GetResult();
 92     }
 93     public function Display()
 94     {
 95         //底层调用了$this->dtp->AssignSysTag();(global,include,foreach,var,runphp)
 96         $this->dtp->Display();
 97     }
 98 }
 99 
100 $a=new TestView(2);
101 $a->Display();
测试类

 

    
 1 <html lang="en">
 2 <head>
 3     <meta charset="UTF-8">
 4     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 5     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 6     <title>{dede:global.cfg_webname/}</title>
 7 </head>
 8 <body>
 9     {dede:foreach array="testlist"}
10      [field:key /]- [field:value /]
11      {/dede:foreach}
12 
13      <div>
14         {dede:arclist  limit='0,4' flag="p"}
15         <div class='d1arc'><a href="[field:arcurl/]">[field:title/]</a></div>
16         {/dede:arclist} </div>
17      </div>
18      {dede:field.myname /}
19      {dede:mytag}
20          [field:myname/]
21      {/dede:mytag}
22 </body>
23 </html>
测试页面

 

 四、数据库操作分析

  

 1    common.inc.php 核心类分析
 2     1.定义全局变量
 3     2.过滤请求参数
 4     3.加载数据库配置 require_once(DEDEDATA.'/common.inc.php');//line 152
 5     4.设置模板目录变量
 6     5.分页参数的设置
 7     6.自动加载类库处理
 8     7.引入数据库类
 9     8.全局常用函数 require_once(DEDEINC.'/common.func.php'); //在line 368,做了兼容处理,扩展的函数可以直接写在extend.func.php中。
11     9.路由处理,请求分发
12     10.载入小助手配置
13   dedesqli.class.php 
        
        $sql="xxxx";
        $dsql->Execute('name', $sql);
        while ($row = $dsql->GetObject('name')) {
         $arr[] = $row;
        }
14     1.$dsql = $dsqli = $db = new DedeSqli(FALSE);  //line 21 在工程所有文件中均不需要单独初始化这个类,可直接用 $dsql 或 $db 进行操作
15     2.SetQuery($sql) :会自动把SQL语句里的#@__替换为$this->dbPrefix(在配置文件中为$cfg_dbprefix)。并设置$this->queryString
16     3.Execute($id="me", $sql='') //如果sql不为空,内部会调用SetQuery,替换前缀。
18       $this->result[$id] = mysqli_query($this->linkID, $this->queryString); //line 315 执行sql返回执行结果。
19     4.GetOne($sql='',$acctype=MYSQLI_ASSOC) 
20        if(!preg_match("/LIMIT/i",$sql)) $this->SetQuery(preg_replace("/[,;]$/i", '', trim($sql))." LIMIT 0,1;");//line 351        //内部通过正则加上了limit 0,1
21        $this->Execute("one"); //line 354 调用Execute
22     5.GetArray和GetObject
function GetObject($id="me")
{
if($this->result[$id]===0)
{
return FALSE;
}
else
{
return mysqli_fetch_object($this->result[$id]);
}
}
23     6.ExecuteNoneQuery($sql='')执行一个不返回结果的SQL语句,如update,delete,insert等

  五、总结

    dedecms 就两个核心类 dedetag.class.php、common.inc.php。一行行读源码,就可以知道它得工作原理。二次开发时,需要哪部分就找到对应的源码进行分析。其它的就应该没什么困难了。

  

posted @ 2018-11-01 17:18  mian_wu  阅读(1628)  评论(0编辑  收藏  举报