CrossPHP
  • Namespace
  • Class
  • Download

Namespaces

  • Cross
    • Auth
    • Cache
      • Driver
      • Request
    • Core
    • DB
      • Connecter
      • Drivers
      • SQLAssembler
    • Exception
    • Http
    • I
    • Lib
      • Document
    • Module
    • MVC
    • Runtime
  • None

Classes

  • Cross\Auth\CookieAuth
  • Cross\Auth\SessionAuth
  • Cross\Cache\Driver\FileCacheDriver
  • Cross\Cache\Driver\MemcacheDriver
  • Cross\Cache\Driver\RedisDriver
  • Cross\Cache\Request\FileCache
  • Cross\Cache\Request\Memcache
  • Cross\Cache\Request\RedisCache
  • Cross\Cache\RequestCache
  • Cross\Core\Annotate
  • Cross\Core\Application
  • Cross\Core\ArrayMap
  • Cross\Core\Config
  • Cross\Core\CrossArray
  • Cross\Core\Delegate
  • Cross\Core\FrameBase
  • Cross\Core\Helper
  • Cross\Core\HttpAuth
  • Cross\Core\Loader
  • Cross\Core\Rest
  • Cross\Core\Router
  • Cross\DB\Connecter\BaseConnecter
  • Cross\DB\Connecter\MySQLConnecter
  • Cross\DB\Connecter\PgSQLConnecter
  • Cross\DB\Connecter\SQLiteConnecter
  • Cross\DB\DBFactory
  • Cross\DB\Drivers\CouchDriver
  • Cross\DB\Drivers\MongoDriver
  • Cross\DB\Drivers\PDOSqlDriver
  • Cross\DB\SQLAssembler\MySQLAssembler
  • Cross\DB\SQLAssembler\PgSQLAssembler
  • Cross\DB\SQLAssembler\SQLAssembler
  • Cross\DB\SQLAssembler\SQLiteAssembler
  • Cross\Http\Request
  • Cross\Http\Response
  • Cross\Lib\Array2XML
  • Cross\Lib\Document\CallTree
  • Cross\Lib\Document\CallTreeToHTML
  • Cross\Lib\Document\HTML
  • Cross\Lib\StringToPHPStream
  • Cross\Module\SQLModule
  • Cross\MVC\Controller
  • Cross\MVC\Module
  • Cross\MVC\View
  • Cross\Runtime\ClosureContainer

Interfaces

  • Cross\I\CacheInterface
  • Cross\I\HttpAuthInterface
  • Cross\I\PDOConnecter
  • Cross\I\RequestCacheInterface
  • Cross\I\RouterInterface
  • Cross\I\SqlInterface

Exceptions

  • Cross\Exception\CacheException
  • Cross\Exception\CoreException
  • Cross\Exception\CrossException
  • Cross\Exception\FrontException

Functions

  • ascLogo
  • line
  • tBody
  • th
  • tHead
   1 <?php
   2 /**
   3  * Cross - a micro PHP 5 framework
   4  *
   5  * @link        http://www.crossphp.com
   6  * @license     MIT License
   7  */
   8 
   9 namespace Cross\MVC;
  10 
  11 use Cross\Exception\CoreException;
  12 use Cross\Lib\Document\HTML;
  13 use Cross\Lib\Array2XML;
  14 use Cross\Core\FrameBase;
  15 use Cross\Core\Config;
  16 use Cross\Core\Router;
  17 use Cross\Core\Helper;
  18 use Exception;
  19 
  20 /**
  21  * @author wonli <wonli@live.com>
  22  * Class View
  23  * @package Cross\MVC
  24  */
  25 class View extends FrameBase
  26 {
  27     /**
  28      * 默认模板目录
  29      *
  30      * @var string
  31      */
  32     private $tpl_dir;
  33 
  34     /**
  35      * 资源配置
  36      *
  37      * @var array
  38      */
  39     private $res_list;
  40 
  41     /**
  42      * 默认模板路径
  43      *
  44      * @var string
  45      */
  46     private $tpl_base_path;
  47 
  48     /**
  49      * 默认url
  50      *
  51      * @var string
  52      */
  53     private $link_base = null;
  54 
  55     /**
  56      * @var array
  57      */
  58     private $wrap_stack = array();
  59 
  60     /**
  61      * 模板数据
  62      *
  63      * @var array
  64      */
  65     protected $data;
  66 
  67     /**
  68      * 初始化布局文件中的变量
  69      * <pre>
  70      * title 标题
  71      * keywords 关键词
  72      * description 页面描述
  73      *
  74      * layer 布局模板名称
  75      * load_layer 是否加载布局模板
  76      * </pre>
  77      *
  78      * @var array
  79      */
  80     protected $set = array(
  81         'title' => '',
  82         'keywords' => '',
  83         'description' => '',
  84 
  85         'layer' => 'default',
  86         'load_layer' => true,
  87     );
  88 
  89     /**
  90      * 模版扩展文件名
  91      *
  92      * @var string
  93      */
  94     protected $tpl_file_suffix = '.tpl.php';
  95 
  96     /**
  97      * url配置缓存
  98      *
  99      * @var array
 100      */
 101     protected static $url_config_cache = array();
 102 
 103     /**
 104      * 渲染模板
 105      *
 106      * @param null $data
 107      * @param null $method
 108      * @throws CoreException
 109      */
 110     function display($data = null, $method = null)
 111     {
 112         $this->data = $data;
 113         if ($method === null) {
 114             $display_type = $this->config->get('sys', 'display');
 115             if ($display_type && strcasecmp($display_type, 'html') !== 0) {
 116                 $this->set['load_layer'] = false;
 117                 $method = trim($display_type);
 118             } else if ($this->action) {
 119                 $method = $this->action;
 120             } else {
 121                 $method = Router::DEFAULT_ACTION;
 122             }
 123         }
 124 
 125         $this->obRenderAction($data, $method);
 126     }
 127 
 128     /**
 129      * 生成url
 130      *
 131      * @param null|string $controller
 132      * @param null|string|array $params
 133      * @param bool $encrypt_params
 134      * @return string
 135      * @throws CoreException
 136      */
 137     function url($controller = null, $params = null, $encrypt_params = false)
 138     {
 139         static $link_base = null;
 140         if ($link_base === null) {
 141             $link_base = $this->getLinkBase();
 142         }
 143 
 144         if ($controller === null && $params === null) {
 145             return $link_base;
 146         } else {
 147             $uri = $this->makeUri($this->getAppName(), false, $controller, $params, $encrypt_params);
 148             return $link_base . $uri;
 149         }
 150     }
 151 
 152     /**
 153      * @see View::url() 生成加密连接
 154      * @param null|string $controller
 155      * @param null|string|array $params
 156      * @return string
 157      * @throws CoreException
 158      */
 159     function sUrl($controller = null, $params = null)
 160     {
 161         return $this->url($controller, $params, true);
 162     }
 163 
 164     /**
 165      * 超链接
 166      *
 167      * @param string $content
 168      * @param string $href
 169      * @param array $element_tags
 170      * @return mixed|string
 171      */
 172     function a($content, $href = '', array $element_tags = array())
 173     {
 174         $element_tags['href'] = $href;
 175         $element_tags['@content'] = $content;
 176         return $this->wrapTag('a', $element_tags);
 177     }
 178 
 179     /**
 180      * 输出img标签
 181      *
 182      * @param string $src
 183      * @param array $element_tags
 184      * @return mixed|string
 185      */
 186     function img($src, array $element_tags = array())
 187     {
 188         $element_tags['src'] = $src;
 189         $element_tags += array('border' => 0, 'alt' => 'image');
 190         return $this->wrapTag('img', $element_tags);
 191     }
 192 
 193     /**
 194      * input标签
 195      *
 196      * @param string $type
 197      * @param array $element_tags
 198      * @return mixed|string
 199      */
 200     function input($type, array $element_tags = array())
 201     {
 202         $element_tags['type'] = $type;
 203         return $this->wrapTag('input', $element_tags);
 204     }
 205 
 206     /**
 207      * 单选
 208      *
 209      * @see View::buildRadioOrCheckbox
 210      * @param array $data
 211      * @param string $default_value
 212      * @param array $radio_tags
 213      * @param array $label_tags
 214      * @return string
 215      */
 216     function radio(array $data, $default_value = '', array $radio_tags = array(), array $label_tags = array())
 217     {
 218         $default_value = array($default_value => true);
 219         return $this->buildRadioOrCheckbox('radio', $data, $default_value, $radio_tags, $label_tags);
 220     }
 221 
 222     /**
 223      * 多选
 224      *
 225      * @see View::buildRadioOrCheckbox
 226      * @param array $data
 227      * @param string|array $default_value
 228      * @param array $checkbox_tags
 229      * @param array $label_tags
 230      * @return string
 231      */
 232     function checkbox(array $data, $default_value = '', array $checkbox_tags = array(), array $label_tags = array())
 233     {
 234         if (is_array($default_value)) {
 235             $default_value = array_flip($default_value);
 236         } else {
 237             $default_value = array($default_value => true);
 238         }
 239 
 240         return $this->buildRadioOrCheckbox('checkbox', $data, $default_value, $checkbox_tags, $label_tags);
 241     }
 242 
 243     /**
 244      * 输出select
 245      *
 246      * @param array $options_data 二维数组时, 生成optgroup
 247      * @param int|string|array $default_value
 248      * @param array $select_params
 249      * @param array $user_option_params
 250      * @return mixed
 251      */
 252     function select(array $options_data, $default_value = null, array $select_params = array(), array $user_option_params = array())
 253     {
 254         $content = '';
 255         if (is_array($default_value)) {
 256             $default_value = array_flip($default_value);
 257         } else {
 258             $default_value = array($default_value => true);
 259         }
 260 
 261         foreach ($options_data as $value => $option) {
 262             $option_params = array();
 263             if (!empty($user_option_params)) {
 264                 $option_params = $user_option_params;
 265             }
 266 
 267             if (is_array($option)) {
 268                 $opt_content = '';
 269                 foreach ($option as $opt_value => $opt_option) {
 270                     unset($option_params['selected']);
 271                     $option_params['value'] = $opt_value;
 272                     $option_params['@content'] = $opt_option;
 273                     if (isset($default_value[$opt_value])) {
 274                         $option_params['selected'] = true;
 275                     }
 276 
 277                     $opt_content .= self::htmlTag('option', $option_params);
 278                 }
 279 
 280                 $opt_params['label'] = $value;
 281                 $opt_params['@content'] = $opt_content;
 282                 $content .= self::htmlTag('optgroup', $opt_params);
 283             } else {
 284                 $option_params['value'] = $value;
 285                 $option_params['@content'] = $option;
 286                 if (isset($default_value[$value])) {
 287                     $option_params['selected'] = true;
 288                 }
 289 
 290                 $content .= self::htmlTag('option', $option_params);
 291             }
 292         }
 293 
 294         $select_params['@content'] = $content;
 295         return $this->wrapContent(self::htmlTag('select', $select_params), false);
 296     }
 297 
 298     /**
 299      * 输出HTML
 300      * <pre>
 301      * 带wrap时, 先处理wrap
 302      * 单独输出HTML内容时候, $encode表示是否转换HTML实体
 303      * </pre>
 304      *
 305      * @param string $content 内容
 306      * @param bool $encode 是否转码
 307      * @return mixed
 308      */
 309     function html($content, $encode = true)
 310     {
 311         return $this->wrapContent($content, $encode);
 312     }
 313 
 314     /**
 315      * 输出任意HTML标签
 316      *
 317      * @param $element
 318      * @param array $element_tags
 319      * @return string
 320      */
 321     static function htmlTag($element, $element_tags = array())
 322     {
 323         return HTML::$element($element_tags);
 324     }
 325 
 326     /**
 327      * HTML标签入栈
 328      *
 329      * @param string $element
 330      * @param string|array $element_tags
 331      * @param bool $content_rear 自身内容是否放在被包裹内容之后
 332      * @return $this
 333      */
 334     function wrap($element, $element_tags = array(), $content_rear = false)
 335     {
 336         if (!is_array($element_tags)) {
 337             $element_tags = array('@content' => $element_tags);
 338         }
 339 
 340         array_unshift($this->wrap_stack, array($element, $element_tags, $content_rear));
 341         return $this;
 342     }
 343 
 344     /**
 345      * 带wrap的块级元素
 346      *
 347      * @param string $content 内容
 348      * @param array $element_tags
 349      * @param string $element
 350      * @return string
 351      */
 352     function block($content, array $element_tags = array(), $element = 'div')
 353     {
 354         $element_tags['@content'] = $content;
 355         return $this->wrapTag($element, $element_tags);
 356     }
 357 
 358     /**
 359      * 处理带模板的block元素
 360      *
 361      * @param string $tpl_name 模板名称
 362      * @param array $tpl_data 模板中的数据
 363      * @param array $element_tags
 364      * @param string $element
 365      * @return string
 366      */
 367     function section($tpl_name, array $tpl_data = array(), array $element_tags = array(), $element = 'div')
 368     {
 369         return $this->block($this->obRenderTpl($tpl_name, $tpl_data), $element_tags, $element);
 370     }
 371 
 372     /**
 373      * 生成表单
 374      * <pre>
 375      * 使用$this->on('buildForm', ....), 来干预所有生成的表单内容
 376      * </pre>
 377      *
 378      * @param string $tpl_name 包含表单的模板文件路径
 379      * @param array $form_tags 生成表单tag的参数
 380      * @param array $tpl_data 模板数据
 381      * @return string
 382      */
 383     function buildForm($tpl_name, array $form_tags = array(), array $tpl_data = array())
 384     {
 385         $content = $this->delegate->getClosureContainer()->run('buildForm', array($this));
 386         $content .= $this->obRenderTpl($tpl_name, $tpl_data);
 387 
 388         $form_tags += array('action' => '', 'method' => 'post');
 389         $form_tags['@content'] = $content;
 390 
 391         return $this->wrapTag('form', $form_tags);
 392     }
 393 
 394     /**
 395      * 加载指定名称的模板文件
 396      *
 397      * @param string $tpl_name
 398      * @param array|mixed $data
 399      */
 400     function renderTpl($tpl_name, $data = array())
 401     {
 402         include $this->tpl($tpl_name);
 403     }
 404 
 405     /**
 406      * 加载指定绝对路径的文件
 407      *
 408      * @param string $file 文件绝对路径
 409      * @param array $data
 410      */
 411     function renderFile($file, $data = array())
 412     {
 413         include $file;
 414     }
 415 
 416     /**
 417      * 带缓存的renderTpl
 418      *
 419      * @param string $tpl_name
 420      * @param array $data
 421      * @param bool $encode
 422      * @return string
 423      */
 424     function obRenderTpl($tpl_name, array $data = array(), $encode = false)
 425     {
 426         ob_start();
 427         $this->renderTpl($tpl_name, $data);
 428         return $this->wrapContent(ob_get_clean(), $encode);
 429     }
 430 
 431     /**
 432      * 带缓存的renderFile
 433      *
 434      * @param string $file
 435      * @param array $data
 436      * @param bool $encode
 437      * @return string
 438      */
 439     function obRenderFile($file, $data = array(), $encode = false)
 440     {
 441         ob_start();
 442         $this->renderFile($file, $data);
 443         return $this->wrapContent(ob_get_clean(), $encode);
 444     }
 445 
 446     /**
 447      * 模板的绝对路径
 448      *
 449      * @param $tpl_name
 450      * @param bool $get_content 是否读取模板内容
 451      * @param bool $auto_append_suffix 是否自动添加模版后缀
 452      * @return string
 453      */
 454     function tpl($tpl_name, $get_content = false, $auto_append_suffix = true)
 455     {
 456         $file_path = $this->getTplPath() . $tpl_name;
 457         if ($auto_append_suffix) {
 458             $file_path .= $this->tpl_file_suffix;
 459         }
 460 
 461         if (true === $get_content) {
 462             return file_get_contents($file_path, true);
 463         }
 464 
 465         return $file_path;
 466     }
 467 
 468     /**
 469      * 输出JSON
 470      *
 471      * @param $data
 472      */
 473     function JSON($data)
 474     {
 475         $this->set['load_layer'] = false;
 476         $this->delegate->getResponse()->setContentType('json');
 477         echo json_encode($data);
 478     }
 479 
 480     /**
 481      * 输出XML
 482      *
 483      * @param $data
 484      * @param string $root_name
 485      * @throws Exception
 486      */
 487     function XML($data, $root_name = 'root')
 488     {
 489         $this->set['load_layer'] = false;
 490         $this->delegate->getResponse()->setContentType('xml');
 491         echo Array2XML::createXML($root_name, $data)->saveXML();
 492     }
 493 
 494     /**
 495      * 安全的输出数组中的值
 496      *
 497      * @param array $data
 498      * @param string|int $key
 499      * @param string $default_value
 500      * @return string
 501      */
 502     function e(array $data, $key, $default_value = '')
 503     {
 504         if (isset($data[$key])) {
 505             return $data[$key];
 506         }
 507 
 508         return $default_value;
 509     }
 510 
 511     /**
 512      * @see e
 513      * <pre>
 514      * 判断数组中的值是否为empty,否则返回默认值
 515      * </pre>
 516      *
 517      * @param array $data
 518      * @param string|int $key
 519      * @param string $default_value
 520      * @return string
 521      */
 522     function ee(array $data, $key, $default_value = '')
 523     {
 524         if (!empty($data[$key])) {
 525             return $data[$key];
 526         }
 527 
 528         return $default_value;
 529     }
 530 
 531     /**
 532      * 设置layer附加参数
 533      *
 534      * @param $name
 535      * @param null $value
 536      * @return $this
 537      */
 538     final public function set($name, $value = null)
 539     {
 540         if (is_array($name)) {
 541             $this->set = array_merge($this->set, $name);
 542         } else {
 543             $this->set[$name] = $value;
 544         }
 545 
 546         return $this;
 547     }
 548 
 549     /**
 550      * 生成资源文件路径
 551      *
 552      * @param $res_url
 553      * @param bool $use_static_url
 554      * @return string
 555      */
 556     function res($res_url, $use_static_url = true)
 557     {
 558         static $res_base_url = null;
 559         if (!isset($res_base_url[$use_static_url])) {
 560             if ($use_static_url) {
 561                 $base_url = $this->config->get('static', 'url');
 562             } else {
 563                 $base_url = $this->config->get('url', 'full_request');
 564             }
 565 
 566             $res_base_url[$use_static_url] = rtrim($base_url, '/') . '/';
 567         }
 568 
 569         return $res_base_url[$use_static_url] . $res_url;
 570     }
 571 
 572     /**
 573      * 输出资源相对路径
 574      *
 575      * @param string $res_url
 576      * @param string $res_dir
 577      * @return string
 578      */
 579     function relRes($res_url, $res_dir = 'static')
 580     {
 581         static $res_base_url = null;
 582         if (null === $res_base_url) {
 583             $res_base_url = rtrim($this->config->get('url', 'request'), '/') . '/' . $res_dir . '/';
 584         }
 585 
 586         return $res_base_url . $res_url;
 587     }
 588 
 589     /**
 590      * @see View::url()
 591      * @param null|string $controller 控制器:方法
 592      * @param null|string|array $params
 593      * @return string
 594      * @throws CoreException
 595      */
 596     function link($controller = null, $params = null)
 597     {
 598         return $this->url($controller, $params);
 599     }
 600 
 601     /**
 602      * @see View::sUrl()
 603      * @param null|string $controller
 604      * @param null|string|array $params
 605      * @return string
 606      * @throws CoreException
 607      */
 608     function slink($controller = null, $params = null)
 609     {
 610         return $this->url($controller, $params, true);
 611     }
 612 
 613     /**
 614      * 生成指定app,指定控制器的url
 615      *
 616      * @param string $base_link
 617      * @param string $app_name
 618      * @param null|string $controller
 619      * @param null|string|array $params
 620      * @param null|bool $encrypt_params
 621      * @return string
 622      * @throws CoreException
 623      */
 624     function appUrl($base_link, $app_name, $controller = null, $params = null, $encrypt_params = null)
 625     {
 626         $base_link = rtrim($base_link, '/') . '/';
 627         if ($controller === null && $params === null) {
 628             return $base_link;
 629         } else {
 630             $uri = $this->makeUri($app_name, true, $controller, $params, $encrypt_params);
 631             return $base_link . $uri;
 632         }
 633     }
 634 
 635     /**
 636      * 清除link中使用到的缓存(config->url配置在运行过程中发生变动时先清除缓存)
 637      */
 638     function cleanLinkCache()
 639     {
 640         unset(self::$url_config_cache[$this->getAppName()]);
 641     }
 642 
 643     /**
 644      * 设置模板dir
 645      *
 646      * @param $dir_name
 647      */
 648     function setTplDir($dir_name)
 649     {
 650         $this->tpl_dir = $dir_name;
 651     }
 652 
 653     /**
 654      * 获取生成连接的基础路径
 655      *
 656      * @return string
 657      */
 658     function getLinkBase()
 659     {
 660         if (null === $this->link_base) {
 661             $this->setLinkBase($this->config->get('url', 'full_request'));
 662         }
 663 
 664         return $this->link_base;
 665     }
 666 
 667     /**
 668      * 获取当前app名称
 669      *
 670      * @return array|string
 671      */
 672     function getAppName()
 673     {
 674         static $app_name = null;
 675         if ($app_name === null) {
 676             $app_name = $this->config->get('app', 'name');
 677         }
 678 
 679         return $app_name;
 680     }
 681 
 682     /**
 683      * 设置生成的连接基础路径
 684      *
 685      * @param $link_base
 686      */
 687     function setLinkBase($link_base)
 688     {
 689         $this->link_base = rtrim($link_base, '/') . '/';
 690     }
 691 
 692     /**
 693      * 模板路径
 694      *
 695      * @return string 要加载的模板路径
 696      */
 697     function getTplPath()
 698     {
 699         static $tpl_path;
 700         $app_name = $this->getAppName();
 701         if (!isset($tpl_path[$app_name])) {
 702             $tpl_path[$app_name] = $this->getTplBasePath() . $this->getTplDir() . DIRECTORY_SEPARATOR;
 703         }
 704 
 705         return $tpl_path[$app_name];
 706     }
 707 
 708     /**
 709      * 设置模板路径
 710      *
 711      * @param $tpl_base_path
 712      */
 713     function setTplBasePath($tpl_base_path)
 714     {
 715         $this->tpl_base_path = rtrim($tpl_base_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
 716     }
 717 
 718     /**
 719      * 获取模板默认路径
 720      *
 721      * @return string
 722      */
 723     function getTplBasePath()
 724     {
 725         if (!$this->tpl_base_path) {
 726             $this->setTplBasePath($this->config->get('app', 'path') . 'templates' . DIRECTORY_SEPARATOR);
 727         }
 728 
 729         return $this->tpl_base_path;
 730     }
 731 
 732     /**
 733      * 取得模板路径前缀
 734      *
 735      * @return string
 736      */
 737     function getTplDir()
 738     {
 739         if (!$this->tpl_dir) {
 740             $default_tpl_dir = $this->config->get('sys', 'default_tpl_dir');
 741             if (!$default_tpl_dir) {
 742                 $default_tpl_dir = 'default';
 743             }
 744             $this->setTplDir($default_tpl_dir);
 745         }
 746 
 747         return $this->tpl_dir;
 748     }
 749 
 750     /**
 751      * 运行时分组添加css/js
 752      *
 753      * @param $res_url
 754      * @param string $location
 755      * @param bool $convert
 756      */
 757     function addRes($res_url, $location = 'header', $convert = true)
 758     {
 759         $this->res_list[$location][] = array(
 760             'url' => $res_url,
 761             'convert' => $convert
 762         );
 763     }
 764 
 765     /**
 766      * 分组加载css|js
 767      *
 768      * @param string $location
 769      * @return string
 770      */
 771     function loadRes($location = 'header')
 772     {
 773         $result = '';
 774         if (empty($this->res_list) || empty($this->res_list[$location])) {
 775             return $result;
 776         }
 777 
 778         if (isset($this->res_list[$location]) && !empty($this->res_list[$location])) {
 779             $data = $this->res_list[$location];
 780         }
 781 
 782         if (!empty($data)) {
 783             if (is_array($data)) {
 784                 foreach ($data as $r) {
 785                     $result .= $this->outputResLink($r['url'], $r['convert']);
 786                 }
 787             } else {
 788                 $result .= $this->outputResLink($data);
 789             }
 790         }
 791 
 792         return $result;
 793     }
 794 
 795     /**
 796      * 生成连接
 797      *
 798      * @param string $app_name
 799      * @param bool $check_app_name
 800      * @param null|string $controller
 801      * @param null|array $params
 802      * @param null|bool $encrypt_params
 803      * @return string
 804      * @throws CoreException
 805      */
 806     protected function makeUri($app_name, $check_app_name, $controller = null, $params = null, $encrypt_params = null)
 807     {
 808         $uri = '';
 809         $enable_controller_cache = false;
 810         //在运行过程中,如果url的配置有变化,需要调用cleanLinkCache()来刷新缓存
 811         if (!isset(self::$url_config_cache[$app_name])) {
 812             $this_app_name = $app_name;
 813             if ($check_app_name) {
 814                 $this_app_name = $this->getAppName();
 815             }
 816 
 817             if ($check_app_name && $app_name != $this_app_name) {
 818                 $config = Config::load(APP_PATH_DIR . $app_name . DIRECTORY_SEPARATOR . 'init.php');
 819             } else {
 820                 $config = $this->config;
 821             }
 822 
 823             $url_router_config = array(
 824                 'url' => $config->get('url'),
 825                 'router' => $config->get('router')
 826             );
 827             self::$url_config_cache[$app_name] = $url_router_config;
 828         } else {
 829             $enable_controller_cache = true;
 830             $url_router_config = self::$url_config_cache[$app_name];
 831         }
 832 
 833         $url_params = '';
 834         $has_controller_string = true;
 835         $url_controller = $this->makeControllerUri($app_name, $enable_controller_cache, $controller, $url_router_config);
 836         if ($url_controller === '') {
 837             $has_controller_string = false;
 838         }
 839 
 840         $url_config = &$url_router_config['url'];
 841         if (!empty($params)) {
 842             $url_params = $this->makeParams($params, $url_config, $encrypt_params, $has_controller_string);
 843         }
 844 
 845         if (!empty($url_config['ext'])) {
 846             switch ($url_config['type']) {
 847                 case 2:
 848                     if ($has_controller_string) {
 849                         $uri .= $url_controller . $url_config['ext'];
 850                     }
 851 
 852                     $uri .= $url_params;
 853                     break;
 854                 case 1:
 855                 case 3:
 856                 case 4:
 857                 case 5:
 858                     $uri .= $url_controller . $url_params . $url_config['ext'];
 859                     break;
 860             }
 861         } else {
 862             $uri .= $url_controller . $url_params;
 863         }
 864 
 865         return $uri;
 866     }
 867 
 868     /**
 869      * 生成控制器连接
 870      *
 871      * @param string $app_name
 872      * @param bool $use_cache 是否使用缓存
 873      * @param string $controller
 874      * @param array $url_config
 875      * @return string
 876      * @throws CoreException
 877      */
 878     protected function makeControllerUri($app_name, $use_cache, $controller, array $url_config)
 879     {
 880         static $path_cache;
 881         if (isset($path_cache[$app_name][$controller]) && $use_cache) {
 882             return $path_cache[$app_name][$controller];
 883         }
 884 
 885         $app_alias_config = $this->parseControllerAlias($app_name, $url_config['router']);
 886         if (isset($app_alias_config[$controller])) {
 887             $real_controller = $app_alias_config[$controller];
 888         } else {
 889             $real_controller = $controller;
 890         }
 891 
 892         $action_name = null;
 893         if (false !== strpos($real_controller, ':')) {
 894             list($controller_name, $action_name) = explode(':', $real_controller);
 895         } else {
 896             $controller_name = $real_controller;
 897         }
 898 
 899         $url = &$url_config['url'];
 900         $index = $this->makeIndex($url, true);
 901         $controller_path = $index . $controller_name;
 902 
 903         if (null !== $action_name) {
 904             $controller_path .= $url['dot'] . $action_name;
 905         }
 906 
 907         $path_cache[$app_name][$controller] = $controller_path;
 908         return $controller_path;
 909     }
 910 
 911     /**
 912      * 生成URL中的索引部分
 913      *
 914      * @param array $url_config
 915      * @param bool $have_controller
 916      * @return string
 917      * @throws CoreException
 918      */
 919     protected function makeIndex(array $url_config, $have_controller = false)
 920     {
 921         static $cache = array();
 922         if (isset($cache[$have_controller])) {
 923             return $cache[$have_controller];
 924         }
 925 
 926         $index = $url_config['index'];
 927         $is_default_index = (0 === strcasecmp($index, 'index.php'));
 928 
 929         switch ($url_config['type']) {
 930             case 1:
 931             case 3:
 932                 $index_dot = '?';
 933                 $addition_dot = '/';
 934                 if ($is_default_index) {
 935                     $index = '';
 936                 }
 937                 break;
 938 
 939             case 2:
 940             case 4:
 941             case 5:
 942                 $index_dot = '/';
 943                 $addition_dot = '';
 944                 break;
 945 
 946             default:
 947                 throw new CoreException('Type does not support!');
 948         }
 949 
 950         if ($url_config['rewrite']) {
 951             $index = $index_dot = $addition_dot = '';
 952         }
 953 
 954         $virtual_path = &$url_config['virtual_path'];
 955         if ($have_controller) {
 956             $index .= $index_dot . $addition_dot;
 957             if ($virtual_path) {
 958                 $index .= $virtual_path . $url_config['dot'];
 959             }
 960         } else {
 961             if ($is_default_index) {
 962                 $index = '';
 963             }
 964 
 965             if ($virtual_path) {
 966                 $index .= $index_dot . $addition_dot . $virtual_path;
 967                 if ($url_config['ext']) {
 968                     $index .= $url_config['ext'];
 969                 }
 970             }
 971         }
 972 
 973         $cache[$have_controller] = $index;
 974         return $index;
 975     }
 976 
 977     /**
 978      * 生成uri参数字符串
 979      *
 980      * @param array $params 当url_type的值不为2时, 值必须是标量(bool型需要在外部转换为int型)
 981      * @param array $url_config
 982      * @param bool $encrypt_params
 983      * @param bool $add_prefix_dot 当控制器字符串为空时,参数不添加前缀
 984      * @return string
 985      */
 986     protected function makeParams(array $params, array $url_config, $encrypt_params = false, $add_prefix_dot = true)
 987     {
 988         $url_dot = &$url_config['dot'];
 989         $params_dot = &$url_config['params_dot'];
 990         if ($params_dot) {
 991             $dot = $params_dot;
 992         } else {
 993             $dot = $url_dot;
 994         }
 995 
 996         $url_params = '';
 997         if ($params) {
 998             switch ($url_config['type']) {
 999                 case 1:
1000                 case 5:
1001                     $url_params = implode($dot, $params);
1002                     break;
1003 
1004                 case 2:
1005                     $url_dot = '?';
1006                     $add_prefix_dot = true;
1007                     $url_params = http_build_query($params);
1008                     break;
1009 
1010                 case 3:
1011                 case 4:
1012                     foreach ($params as $p_key => $p_val) {
1013                         $url_params .= $p_key . $dot . $p_val . $dot;
1014                     }
1015                     $url_params = rtrim($url_params, $dot);
1016                     break;
1017             }
1018 
1019             if (true === $encrypt_params) {
1020                 $url_params = $this->urlEncrypt($url_params);
1021             }
1022         }
1023 
1024         if ($add_prefix_dot) {
1025             return $url_dot . $url_params;
1026         }
1027 
1028         return $url_params;
1029     }
1030 
1031     /**
1032      * 输出js/css连接
1033      *
1034      * @param $res_link
1035      * @param bool $make_link
1036      * @return null|string
1037      */
1038     protected function outputResLink($res_link, $make_link = true)
1039     {
1040         $t = Helper::getExt($res_link);
1041         switch (strtolower($t)) {
1042             case 'js' :
1043                 $tpl = '<script type="text/javascript" src="%s"></script>';
1044                 break;
1045 
1046             case 'css' :
1047                 $tpl = '<link rel="stylesheet" type="text/css" href="%s"/>';
1048                 break;
1049 
1050             default :
1051                 $tpl = null;
1052         }
1053 
1054         if (null !== $tpl) {
1055             if ($make_link) {
1056                 $res_link = $this->res($res_link);
1057             }
1058 
1059             return sprintf("{$tpl}\n", $res_link);
1060         }
1061 
1062         return null;
1063     }
1064 
1065     /**
1066      * 加载布局
1067      *
1068      * @param string $content
1069      * @param string $layer_ext
1070      * @throws CoreException
1071      */
1072     protected function loadLayer($content, $layer_ext = '.layer.php')
1073     {
1074         $layer_file = $this->getTplPath() . $this->set['layer'] . $layer_ext;
1075         if (!is_file($layer_file)) {
1076             throw new CoreException($layer_file . ' layer Not found!');
1077         }
1078 
1079         extract($this->set, EXTR_PREFIX_SAME, 'USER_DEFINED');
1080         include $layer_file;
1081     }
1082 
1083     /**
1084      * 输出带layer的view
1085      *
1086      * @param array $data
1087      * @param string $method
1088      * @return string|void
1089      * @throws CoreException
1090      */
1091     private function obRenderAction($data, $method)
1092     {
1093         ob_start();
1094         $this->$method($data);
1095         $content = ob_get_clean();
1096 
1097         if ($this->set['load_layer']) {
1098             $this->loadLayer($content);
1099         } else {
1100             echo $content;
1101         }
1102     }
1103 
1104     /**
1105      * 解析路由别名配置
1106      *
1107      * @param string $app_name
1108      * @param array $router
1109      * @return array
1110      */
1111     private function parseControllerAlias($app_name, array $router)
1112     {
1113         static $router_alias_cache;
1114         if (!isset($router_alias_cache[$app_name])) {
1115             $router_alias_cache[$app_name] = array();
1116             if (!empty($router)) {
1117                 foreach ($router as $controller_alias => $alias_config) {
1118                     $router_alias_cache[$app_name][$alias_config] = $controller_alias;
1119                 }
1120             }
1121         }
1122 
1123         return $router_alias_cache[$app_name];
1124     }
1125 
1126     /**
1127      * 生成radio或checkbox标签
1128      *
1129      * @param string $type 指定类型
1130      * @param array $data 数据 值和label的关联数组
1131      * @param array $default_value 默认值
1132      * @param array $input_tags input附加参数
1133      * @param array $label_tags label附加参数
1134      * @return string
1135      */
1136     private function buildRadioOrCheckbox($type, array $data, array $default_value = array(), array $input_tags = array(), array $label_tags = array())
1137     {
1138         $content = '';
1139         foreach ($data as $value => $label_text) {
1140             $build_input_tags = array();
1141             if (!empty($input_tags)) {
1142                 $build_input_tags = $input_tags;
1143             }
1144 
1145             $build_input_tags['type'] = $type;
1146             $build_input_tags['value'] = $value;
1147             if (isset($default_value[$value])) {
1148                 $build_input_tags['checked'] = true;
1149             }
1150 
1151             $label_tags['@content'] = self::htmlTag('input', $build_input_tags) . $label_text;
1152             $content .= self::htmlTag('label', $label_tags);
1153         }
1154 
1155         return $this->wrapContent($content, false);
1156     }
1157 
1158     /**
1159      * 处理wrap
1160      *
1161      * @param array $wrap_tags
1162      * @return mixed
1163      */
1164     private function buildWrapTags(array &$wrap_tags)
1165     {
1166         $i = 0;
1167         $wrap_content = '';
1168         $stack_size = count($wrap_tags) - 1;
1169         while ($wrap_config = array_shift($wrap_tags)) {
1170             list($wrap_element, $wrap_element_tags, $after) = $wrap_config;
1171             if ($wrap_content === '') {
1172                 $wrap_content = HTML::$wrap_element($wrap_element_tags);
1173             } else {
1174                 if (isset($wrap_element_tags['@content']) && $after) {
1175                     $wrap_element_tags['@content'] = $wrap_content . $wrap_element_tags['@content'];
1176                 } else if (isset($wrap_element_tags['@content'])) {
1177                     $wrap_element_tags['@content'] .= $wrap_content;
1178                 } else {
1179                     $wrap_element_tags['@content'] = $wrap_content;
1180                 }
1181 
1182                 if ($i == $stack_size) {
1183                     return self::htmlTag($wrap_element, $wrap_element_tags);
1184                 } else {
1185                     $wrap_content = HTML::$wrap_element($wrap_element_tags);
1186                 }
1187             }
1188             $i++;
1189         }
1190 
1191         return $wrap_content;
1192     }
1193 
1194     /**
1195      * 处理带wrap的HTML
1196      *
1197      * @param string $content
1198      * @param bool $encode 是否转码
1199      * @return mixed
1200      */
1201     private function wrapContent($content, $encode = true)
1202     {
1203         if (!empty($this->wrap_stack)) {
1204             $stack_top = &$this->wrap_stack[0];
1205             if (isset($stack_top[1]['@content']) && $stack_top[2]) {
1206                 $content .= $stack_top[1]['@content'];
1207             } else if (isset($stack_top[1]['@content'])) {
1208                 $content = $stack_top[1]['@content'] . $content;
1209             }
1210 
1211             $stack_top[1]['@content'] = $content;
1212             return $this->buildWrapTags($this->wrap_stack);
1213         } else if ($encode) {
1214             return htmlentities($content, ENT_IGNORE);
1215         } else {
1216             return $content;
1217         }
1218     }
1219 
1220     /**
1221      * 节点入栈并生成HTML
1222      *
1223      * @param string $element
1224      * @param array $element_tags
1225      * @return mixed|string
1226      */
1227     private function wrapTag($element, $element_tags = array())
1228     {
1229         if (!empty($this->wrap_stack)) {
1230             $this->wrap($element, $element_tags);
1231             return $this->buildWrapTags($this->wrap_stack);
1232         }
1233 
1234         return self::htmlTag($element, $element_tags);
1235     }
1236 }
1237 
CrossPHP API documentation generated by ApiGen