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/)和字段的解析是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 13
4 读取要解析的模板
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/)
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
2require_once(dirname(__FILE__)."/../include/common.inc.php");
3require_once(DEDEINC.'/channelunit.class.php');
4require_once(DEDEINC.'/typelink.class.php');
5require_once(DEDEINC.'/ftp.class.php');
6/**
7 * 模板调⽤事例
8 *
9 * @version        2018-11-01
10 * @package        1.0.1
11 * @author        main_wu
12*/
13class TestView
14 {
15public$dsql;
16public$dtp;
17public$TypeID;
18public$Fields;
19public$TypeLink;
20public$pvCopy;
21public$refObj;
22public$ftp;
23public$remoteDir;
24
25public function __construct($typeid=0, $needtypelink=true)
26    {
27global$_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//字段,通过{ame}访问到。在display时,由$this->dtp->AssignSysTag()处理
39        //如果需要⾯包屑导航等信息,则要new TypeLink,原理也是往Fields中在赋值
40if ($needtypelink) {
41$this->TypeLink = new TypeLink($typeid);
42if (is_array($this->TypeLink->TypeInfos)) {
43foreach ($this->TypeLink->TypeInfos as$k=>$v) {
44if (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//全局变量,可以通过{stlist}访问到。在display时,由$this->dtp->AssignSysTag()处理 59$GLOBALS['testlist']=array(1,2,3,4,5);
60
61
62//解析框架⾃定义模板,arclist/
63        MakeOneTag($this->dtp, $this);
64//解析⾃⼰定义模板,沒有⾃定义则此代码不需要。
65foreach ($this->dtp->CTags as$tid => $ctag) {
66if ($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    }
79public function Mytag($innertext)
80    {
81//重新初始化底层解析模板。
82$dtp2 = new DedeTagParse();
83$dtp2->SetNameSpace('field', '[', ']');
84$dtp2->LoadSource($innertext);
85foreach ($dtp2->CTags as$k=>$ctag) {
86if ($ctag->GetName()=='myname') {
87//此处赋的值,⾃⾏处理
88$dtp2->Assign($k, "mian_wu");
89            }
90        }
91return$dtp2->GetResult();
92    }
93public 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      {ame /}
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)
20if(!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。⼀⾏⾏读源码,就可以知道它得⼯作原理。⼆次开发时,需要哪部分就到对应的源码进⾏分析。其它的就应该没什么困难了。