龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > php编程 >

MVC的调度器和模板类

时间:2014-07-22 14:52来源: 作者: 点击:
分享到:
调整了设置参数的的方法br / 新增了普通路由模式br / pathinfo模式支持伪静态了br / pathinfo现在支持用户自定义路由了br /
调整了设置参数的的方法
新增了普通路由模式
pathinfo模式支持伪静态了
pathinfo现在支持用户自定义路由了

<?php

/**
 * {loop $array $key $value}..........{/loop} 循环
 * {loop $array $value}..........{/loop} 循环
 * {if condition}...{elseif condition}..{else}..{/if} if条件语句
 * {$val} 输出变量值
 * {eval echo "ok";} 运行PHP代码
 * {template file} 包含另外一个模版
 */
class Template {

    private static $tDir; //模版文件目录
    private static $tTmpDir; //编译好后的文件目录
    private $tVal;  //模版变量
    private $tFile; //模版文件
    private $tContent; //模版内容
    private static $uDispatcher; //URL调度器
    private static $real = false; //实时编译

    public function __construct() {
        $this->tVal = array();
    }

    /**
     * 设置模版文件目录
     * @param string $dir
     */
    public static function setTemplateDir($dir) {
        self::$tDir = $dir;
    }

    /**
     * 是否实时编译
     * @param bool $real
     */
    public static function setReal($real) {
        self::$real = (bool) $real;
    }

    /**
     * 临时文件目录
     * @param string $dir
     */
    public static function setTmpDir($dir) {
        if (!file_exists($dir)) {
            if (!mkdir($dir, 0, true))
                die("tmp dir $dir can't to mkdir");
        }
        self::$tTmpDir = realpath($dir);
    }

    /**
     * URL调度器
     * @param Dispatcher $dispatcher
     */
    public static function setU(&$dispatcher) {
        if (is_object($dispatcher) && method_exists($dispatcher, 'U')) {
            self::$uDispatcher = $dispatcher;
        }
    }

    /**
     * 变量赋值
     * @param mixed $name
     * @param mixed $value
     */
    public function assign($name, $value) {
        $this->tVal[$name] = $value;
    }

    /**
     * 取得模版的变量
     * @param string $name
     */
    public function getVal($name) {
        if (isset($this->tVal[$name])) {
            return $this->tVal[$name];
        }else
            return false;
    }

    /**
     * 将运行好后的内容,保存到一个html文件中
     * @param string $tFile
     * @param string $html
     */
    public function saveHtml($tFile, $html) {
        ob_start();
        $this->display($tFile);
        $buffer = ob_get_contents();
        ob_end_clean();
        file_put_contents($html, $buffer);
    }

    /**
     * 运行并显示模版内容
     * @param string $tfile
     */
    public function display($tFile) {
        $this->tFile = $this->parseTemplatePath($tFile);
        if (!self::$real) {
            if (!file_exists($this->getTmpFile()))
                $this->parse();
            elseif ((filemtime($this->tFile) > filemtime($this->getTmpFile())))
                $this->parse();
        }else
            $this->parse();
        extract($this->tVal, EXTR_OVERWRITE);
        include $this->getTmpFile();
    }

    /**
     * 编译好后的文件
     * @return string $filepath
     */
    private function getTmpFile() {
        $basename = basename($this->tFile);
        $pos = strrpos($basename, '.');
        $tmp = 'tpl_' . substr($basename, 0, $pos) . '.php';
        return self::$tTmpDir . '/' . $tmp;
    }

    private function parse() {
        $this->tContent = file_get_contents($this->tFile);
        $this->parseInclude();
        $this->parseSection();
        $this->parseVal();
        $this->parseEval();
        file_put_contents($this->getTmpFile(), $this->tContent);
    }

    private function parseInclude() {
        $this->tContent = preg_replace("/\{template\s+([a-zA-z0-9\._]+)\}/ies", "\$this->subtemplate('$1')", $this->tContent);
    }

    /**
     * 获取只模版
     * @param string $file
     */
    private function subtemplate($file) {
        return file_get_contents($this->parseTemplatePath($file));
    }

    /**
     * 解析模版路径
     * @param string $file
     * @return string $filepath
     */
    private function parseTemplatePath($tFile) {
        $tFile.='.html';
        $tFile = self::$tDir ? self::$tDir . '/' . $tFile : $tFile;
        if (!file_exists($tFile)) {
            die("No template file $tFile");
        } else {
            $tFile = realpath($tFile);
        }
        return $tFile;
    }

    /**
     * 解析变量
     */
    private function parseVal() {
        $this->tContent = preg_replace("/\{(\\$\S+?)\}/is", "<?php echo \\1 ;?>", $this->tContent);
    }

    /**
     * 解析段落
     */
    private function parseSection() {
        //逻辑
        $this->tContent = preg_replace("/\{elseif\s+(.+?)\}/ies", "\$this->stripvtags('<?php } elseif(\\1) { ?>','')", $this->tContent);
        $this->tContent = preg_replace("/\{else\}/is", "<?php } else { ?>", $this->tContent);
        $this->tContent = preg_replace("/\{U\((.+?)\)\}/ies", "\$this->parseUrl('$1')", $this->tContent);
        //循环
        for ($i = 0; $i < 6; $i++) {
            $this->tContent = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}(.+?)\{\/loop\}/ies", "\$this->stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2) { ?>','\\3<?php } } ?>')", $this->tContent);
            $this->tContent = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}(.+?)\{\/loop\}/ies", "\$this->stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>','\\4<?php } } ?>')", $this->tContent);
            $this->tContent = preg_replace("/\{if\s+(.+?)\}(.+?)\{\/if\}/ies", "\$this->stripvtags('<?php if(\\1) { ?>','\\2<?php } ?>')", $this->tContent);
        }
    }

    private  function stripvtags($expr, $statement='') {
        $expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr));
        $statement = str_replace("\\\"", "\"", $statement);
        return $expr . $statement;
    }

    /**
     * 解析PHP语句
     */
    private function parseEval() {
        $this->tContent = preg_replace("/\{eval\s+(.+?)\}/is", "<?php $1 ?>", $this->tContent);
    }

    /**
     * 解析URL
     */
    private function parseUrl($url) {
        if (is_object(self::$uDispatcher)) {
            return self::$uDispatcher->U($url);
        } else {
            return $url;
        }
    }

}

?>

2. [文件] Dispatcher.class.php ~ 12KB     下载(47)     跳至 [1] [2] [3] [全屏预览]

<?php

/**
 * 控制调度器
 * 先定义APP_PATH常量 制定应用程序目录
 * 默认模块目录 APP_PATH 目录下面的 Action目录
 * 默认控制器为IndexAction
 * 默认模块名为index
 * 默认参数分隔符为"/",可选"-"
 * 默认入口文件为index.php
 * 模块的类名必须和文件同名,比如:IndexModule则它的文件名为IndexModule.class.php
 * 可通过setOption方法设置一些参数
 * pathinfo模式支持伪静态
 * 新增普通url模式
 * setOption参数说明
 * 传进去的是数组键值对形式的参数
 * 设置选项条件,可设置的有
 * MODULE_PATH=>查找模块目录的位置
 * DEFAULT_MODULE=>默认Module
 * DEFAULT_ACTION=>默认Action
 * DEBUG=>开启调试(true|false)
 * URL_MODEL=>路由模式(0:普通模式,1:pathinfo模式)
 * URL_DELIMITER=>参数分隔符 pathinfo模式使用
 * URL_HTML_SUFFIX=>'文件后缀' pathinfo模式伪静态使用
 * ENTRY_INDEX=>入口文件
 * URL_ROUTER_ON=>开启自定义路由
 * 普通URL模式U(模块名/操作名?参1=值1&参2=值2)
 * 路由模式U(路由名@?参1=值1&参2=值2)
 */
class Dispatcher {

    private static $instance;
    private static $_SGLOBAL; //调度配置
    private static $route = array(); //泛路由

    private function __construct() {
        self::initConfig();
    }

    public static function getInstance() {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __clone() {

    }

    /**
     * 运行控制器
     */
    public function run() {
        $route = array();
        if (self::$_SGLOBAL['URL_MODEL'] == 1) {
            $route = $this->pathInfoRoute();
        } else {
            $route = $this->generalRoute();
        }
        $modulefile = self::$_SGLOBAL['MODULE_PATH'] . "/{$route['module']}.class.php";
        if (file_exists($modulefile)) {
            include $modulefile;
            if (class_exists($route['module'])) {
                $class = new $route['module'];
                if (method_exists($class, $route['action'])) {
                    call_user_func(array(&$class, $route['action']));
                }else
                    die("in <b>{$route['module']}</b> module no this <b>{$route['action']}</b> action");
            }else
                die("no this <b>{$route['module']}</b> module");
        }else {
            die("no this <b>{$route['module']}</b> module");
        }
        self::$_SGLOBAL['endtime'] = microtime(true);
        $this->debugInfo();
    }

    /**
     * 输出调试信息
     */
    private function debugInfo() {
        if (self::$_SGLOBAL['DEBUG']) {
            $exectime = self::$_SGLOBAL['endtime'] - self::$_SGLOBAL['starttime'];
            $debuginfo = <<<HTML
            <style type="text/css">
            .dispatcher_debug_table th,.dispatcher_debug_table td{padding:5px;}
            .dispatcher_debug_table th{
            border-top:1px solid red;
            border-left:1px solid red;
            background-color:#ccc;
            }
            .dispatcher_debug_table td{
            border-top:1px solid red;
            border-left:1px solid red;
            border-right:1px solid red;
            }
.dispatcher_debug_table_last td,.dispatcher_debug_table_last th{
            border-bottom:1px solid red;
            }
            .dispatcher_debug_table_title{border-right:1px solid red;}

            </style>
 <table class="dispatcher_debug_table" cellpadding="0" cellspacing="0">
       <tr><th class="dispatcher_debug_table_title">Debug Info</th></tr>
   <tr>
   <th>Execute Time</th><td>$exectime s</td>
   </tr>
   <tr><th>Include File</th><td>
HTML;
            foreach (get_included_files () as $file) {
                $debuginfo.=$file . "<br/>";
            }
            $debuginfo.="<tr><th>Server Info</th><td>";
            $debuginfo.="Host:" . $_SERVER['HTTP_HOST'] . "<br/>";
            $debuginfo.="PHP_Version:" . PHP_VERSION . "<br/>";
            $debuginfo.="Server_Version:" . $_SERVER['SERVER_SOFTWARE'] . "<br/>";
            $debuginfo.="</td></tr>";
            $debuginfo.="<tr class='dispatcher_debug_table_last'><th>Client Info</th><td>";
            $debuginfo.="Remote_Addr:" . $_SERVER['REMOTE_ADDR'] . "<br/>";
            $debuginfo.="User_Agent:" . $_SERVER['HTTP_USER_AGENT'] . "<br/>";
            $debuginfo.="</td></tr>";
            $debuginfo.="</table>";
            echo $debuginfo;
        }
    }

    private function generalRoute() {
        $route = array();
        $route['module'] = !empty($_GET['m']) ? $_GET['m'] : self::$_SGLOBAL['DEFAULT_MODULE'];
        $route['action'] = !empty($_GET['a']) ? $_GET['a'] : self::$_SGLOBAL['DEFAULT_ACTION'];
        $route['module'].='Action';
        unset($_GET['m']);
        unset($_GET['a']);
        return $route;
    }

    /**
     * PATHINFO形式的路由调度
     * 支持伪静态
     */
    private function pathInfoRoute() {
        $route = array();
        //伪静态
        if (self::$_SGLOBAL['URL_HTML_SUFFIX']) {
            $pos = strlen($_SERVER['PATH_INFO']) - strlen(self::$_SGLOBAL['URL_HTML_SUFFIX']);
            $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], 0, $pos);
        }
        if (!$_SERVER['PATH_INFO'] || $_SERVER['PATH_INFO'] == '/') {
            $route = array('module' => self::$_SGLOBAL['DEFAULT_MODULE'],
                'action' => self::$_SGLOBAL['DEFAULT_ACTION']);
        } else {
            $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], 1);
            $pathinfo = explode(self::$_SGLOBAL['URL_DELIMITER'], $_SERVER['PATH_INFO']);
            //用户自定义路由
            if (self::$_SGLOBAL['URL_ROUTER_ON'] && in_array($pathinfo[0], array_keys(self::$route))) {
                $route['module'] = self::$route[$pathinfo[0]][0];
                $route['action'] = self::$route[$pathinfo[0]][1];
                $c = explode(',', self::$route[$pathinfo[0]][2]);
                array_shift($pathinfo);
                foreach ($c as $r) {
                    $_GET[$r] = array_shift($pathinfo);
                }
            } else {
                if (count($pathinfo) < 2) {
                    $route['module'] = $pathinfo[0] . self::$_SGLOBAL['MODULE_SUFFIX'];
                    $route['action'] = self::$_SGLOBAL['DEFAULT_ACTION'] . self::$_SGLOBAL['ACTION_SUFFIX'];
                } else {
                    $route['module'] = array_shift($pathinfo) . self::$_SGLOBAL['MODULE_SUFFIX'];
                    $route['action'] = array_shift($pathinfo) . self::$_SGLOBAL['ACTION_SUFFIX'];
                }
            }
            if (count($pathinfo) >= 2) {
                for ($i = 0, $cnt = count($pathinfo); $i < $cnt; $i++) {
                    if (isset($pathinfo[$i + 1])) {
                        $_GET[$pathinfo[$i]] = $pathinfo[++$i];
                    }
                }
            }
        }
        $route['module'].='Action';
        $_REQUEST = array_merge($_GET, $_POST);
        return $route;
    }

    /**
     * url地址组合
     * 格式为:Module/Action?get=par(模块名/动作名?get参数)
     * @param string $url
     * @return string $url
     */
    public static function U($url) {
        $pathinfo = parse_url($url);
        $path = '';
        $get = array();
        $inroute = false; //用户定义的路由
        if (isset($pathinfo['query'])) {
            $query = explode('&', $pathinfo['query']);
            foreach ($query as $q) {
                list($k, $v) = explode('=', $q);
                $get[$k] = $v;
            }
        }

        if (!self::$_SGLOBAL) {
            self::initConfig();
        }
        //pathinfo方式的url
        if (self::$_SGLOBAL['URL_MODEL'] == 1) {

            if (self::$_SGLOBAL['URL_ROUTER_ON'] && strpos($pathinfo['path'], '@') !== false) {
                //取出所有用户定义的路由
                $routeNames = array_keys(self::$route);
                $p = substr($pathinfo['path'], 0, -1);
                if (in_array($p, $routeNames)) {
                    $inroute = true;
                    $path.='/' . $p;
                    $c = explode(',', self::$route[$p][2]);
                    foreach ($c as $v) {
                        if (isset($get[$v])) {
                            $path.=self::$_SGLOBAL['URL_DELIMITER'] . $get[$v];
                            unset($get[$v]);
                        }
                    }
                }
            }
            if (!$inroute) {
                if (isset($pathinfo['path'])) {
                    list($module, $action) = explode('/', $pathinfo['path']);
                    $module = $module ? $module : self::$_SGLOBAL['DEFAULT_MODULE'];
                    $action = $action ? $action : self::$_SGLOBAL['DEFAULT_ACTION'];
                } else {
                    $module = self::$_SGLOBAL['DEFAULT_MODULE'];
                    $action = self::$_SGLOBAL['DEFAULT_ACTION'];
                }
                $path = "/$module" . self::$_SGLOBAL['URL_DELIMITER'] . $action;
            }
            if (!empty($get)) {
                foreach ($get as $k => $v) {
                    $path.=self::$_SGLOBAL['URL_DELIMITER'] . $k . self::$_SGLOBAL['URL_DELIMITER'] . $v;
                }
            }
            //url伪静态
            if (self::$_SGLOBAL['URL_HTML_SUFFIX']) {
                $path.=self::$_SGLOBAL['URL_HTML_SUFFIX'];
            }
        } elseif (self::$_SGLOBAL['URL_MODEL'] == 0) {
            $url = parse_url($url);
            if (isset($url['path'])) {
                list($module, $action) = explode('/', $url['path']);
                $module = $module ? $module : self::$_SGLOBAL['DEFAULT_MODULE'];
                $action = $action ? $action : self::$_SGLOBAL['DEFAULT_ACTION'];
            } else {
                $module = self::$_SGLOBAL['DEFAULT_MODULE'];
                $action = self::$_SGLOBAL['DEFAULT_ACTION'];
            }
            $path.="?m=$module&a=$action";
            if ($url['query']) {
                $path.='&' . $url['query'];
            }
        }
        if (!self::$_SGLOBAL['URL_REWRITE'])
            $path = '/' . self::$_SGLOBAL['ENTRY_INDEX'] . $path;
        return $path;
    }

    /**
     * 初始化配置信息
     */
    private static function initConfig() {
        if (defined('APP_PATH')) {
            //默认模块目录
            self::$_SGLOBAL['MODULE_PATH'] = APP_PATH . '/action';
        }
        self::$_SGLOBAL['DEFAULT_ACTION'] = 'index'; //默认action
        self::$_SGLOBAL['DEFAULT_MODULE'] = 'Index'; //默认module
        //默认url路由模式,1:pathinfo模式,0为普通模式
        self::$_SGLOBAL['URL_MODEL'] = 1;
        self::$_SGLOBAL['URL_DELIMITER'] = '/'; //参数分隔符
        self::$_SGLOBAL['ENTRY_INDEX'] = 'index.php';
        self::$_SGLOBAL['URL_HTML_SUFFIX'] = null; //url伪静态
        self::$_SGLOBAL['URL_REWRITE'] = false; //URL重写
        self::$_SGLOBAL['starttime'] = microtime(true);
        self::$_SGLOBAL['URL_ROUTER_ON'] = false; //是否启用路由功能
        self::$_SGLOBAL['DEBUG'] = false;
    }

    /**
     * 设置选项条件,可设置的有
     * MODULE_PATH=>查找模块目录的位置
     * DEFAULT_MODULE=>默认Module
     * DEFAULT_ACTION=>默认Action
     * DEBUG=>开启调试(true|false)
     * URL_DELIMITER=>参数分隔符
     * URL_MODEL=>路由模式(0:普通模式,1:pathinfo模式)
     * URL_HTML_SUFFIX=>'文件后缀' pathinfo模式伪静态使用
     * ENTRY_INDEX=>入口文件
     * URL_ROUTER_ON=>开启自定义路由
     * @param array $option 选项
     */
    public function setOption($option) {
        $o = array('MODULE_PATH', 'DEFAULT_MODULE',
            'DEFAULT_ACTION', 'DEBUG',
            'URL_DELIMITER', 'URL_MODEL',
            'URL_HTML_SUFFIX', 'ENTRY_INDEX', 'URL_REWRITE', 'URL_ROUTER_ON');
        foreach ($option as $k => $v) {
            if (in_array($k, $o)) {
                self::$_SGLOBAL[$k] = $v;
            }
        }
    }

    /**
     * 设置路由
     * array('route'=>array('模块名称', '操作名称','参数1,参数2,参数3'))
     * @param array $route 路由
     */
    public function setRoute($route) {
        self::$route = $route;
    }

}

?>

3. [代码][PHP]代码     跳至 [1] [2] [3] [全屏预览]

<?php

include 'action/CommonAction.class.php';
require 'mvc/Dispatcher.class.php';
require 'mvc/Template.class.php';

$dispatcher = Dispatcher::getInstance();

//控制器选项
$option = array('DEBUG' => 1,
    'URL_MODEL' => 1,
    'URL_DELIMITER' => '/',
    'DEFAULT_ACTION' => 'home',
    'URL_REWRITE' => 1,
    'URL_ROUTER_ON' => true,
    'URL_HTML_SUFFIX'=>'.html');

//自定义泛路由
$router = array('space'=>array('Space', 'index','uid'));

$dispatcher->setOption($option);
$dispatcher->setRoute($router);

Template::setU($dispatcher);
Template::setReal(true);
Template::setTemplateDir('template/default');
Template::setTmpDir('runtime/tpl');
$dispatcher->run();
?>
精彩图集

赞助商链接