论坛首页 编程语言技术论坛

简易PHP路由,支持正反向url解析支持

浏览 3134 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-06-21  

几年前实现了一个简单的正向路由,那时候不会写反向路由解析,最近通读qee v3的代码,因为其中已经扣除了路由解析这个功能,故自己结合之前的经验,发现写个简单的正反向路由解析还是蛮简单的,见代码:

 

<?php
/*
 * 静态页配置文件
 * 
 * key	为 pattern
 * 值	为 配置参数
 * 
 * 越上面的优先级越高
 */
return array(
		
	array(		
		'pattern' => 'core-{id}-{name}.html',

		'action'  => 'core/show',
		'config'	=> array(
			'id'	=> '[0-9]+',
			'name'	=> '[a-z][a-z_0-9]+'
		),
		'default'	=> array(
			'id'	=> 2,
			'name'	=> 'sfken'
		),		
	),

	array(
		'pattern' => 'admin.html',
	
		'action'  => 'admin/index',
	),

);

上面是配置文件

 

<?php
class Tool_PageStatic {
	
	private $_obj_id;	
	private $_cache;
	private $_accessor;	
	private $_config = array();
	
	private $_result = array();
		
	function __construct(array $config)
	{
		if ( empty($config['obj_id']) )
        {
        	# 对象标识 用于缓存配置文件等用,标识系统中的 ps 对象的实例标识
        	throw BaseError::invalid_parameters_error('key "obj_id" not set');
        }
        $this->_obj_id = $config['obj_id'];		
        
		$this->_accessor = val( $config , 'accessor' , 'page' );
		$this->_cache = val( $config , 'cache' , NULL );
		
		$cfopt = val( $config , 'config' , null );
		if ( !empty($cfopt) )
		{
			if ( is_array($cfopt) )
			{
				$this->loadConfig($cfopt);
			}
			if ( is_file($cfopt) )
			{
				# 如果是文件是否需要从缓存中进行读取,还是每次都要读取此处的配置文件				
			
				$cfopt = include($cfopt);
				$this->loadConfig( (array) $cfopt);
			}
		}
		
		$cfopt = null;
		
		$this->default = array(
			'action' => Config::get('app.default_action','index'),
			'nocache' => TRUE,
			'params' => array(),
		);
		
	}
	
	private function loadConfig( array $config )
	{
		foreach ( $config as $opts )
		{
			# 对于 未设置 action & pattern 的配置项 直接忽略
			if ( empty($opts['action']) || empty($opts['pattern']) ) continue;
			
			$opts['src_pattern'] = $opts['pattern'];
			
			if ( !empty($opts['config']) )
			{
				foreach($opts['config'] AS $conf_key => $conf_val)
			    {
				    $opts['pattern'] = str_replace('{'.$conf_key.'}', '('.$conf_val.')', $opts['pattern']);
			    }
			}
			else
			{
				$opts['config'] = array();
			}
			if ( empty($opts['default']) ) $opts['default'] = array();
						
			$this->_config[strtolower($opts['action'])] = $opts;
		}
		
		# 解析完成后是否可以存入缓存		
	}
	
	function getAccessor()
	{
		return $this->_accessor;
	}
	
	/**
	 * 解析 string 返回对应的action以及相应的参数
	 *
	 * @param string $string
	 * 
	 * @return array
	 */
	function parsing($string)
	{	
//		dump($this->_config);
			
		if ( empty($string) || empty($this->_config) ) return $this->default;
		
		if ( empty($this->_result[$string]) )
		{
			$d = $this->default;
			
			foreach($this->_config AS $opts)
			{
				if (preg_match('#^'.$opts['pattern'].'/?$#i', $string, $match_result))
				{
//					dump($match_result);
					
					# offset 为0 是 原字符串
			    	$offset = 1;
			    	foreach($opts['config'] AS $conf_key => $conf_val)
			    	{
			    		if(isset($match_result[$offset]))
			    		{
				    		$d['params'][$conf_key] = $match_result[$offset++];
			    		}
			    	}
					
					$d['nocache'] = val($opts,'nocache',$d['nocache']);
					$d['action'] = $opts['action'];
					break;
				}
			}
			
			$this->_result[$string] = $d;
		}
		
		return $this->_result[$string];
	}
	
	/**
	 * 生成静态的 url 地址
	 *
	 * @param string $action_name
	 * @param array $params
	 */
	function psurl( $action_name , array $params = null )
	{
		$opts = val( $this->_config , strtolower($action_name) , null );	
		if ( !empty($opts) )
		{
			$params = (array) $params;
			
			# 使用源 $opts['src_pattern']
			$url = $opts['src_pattern'];
			dump($url);
        	foreach($opts['default'] AS $d_key => $d_val)
        	{
        		if ( !empty($params[$d_key]) )
        		{
        			$d_val = $params[$d_key];
        			unset($params[$d_key]);
        		}        		
//        		$url = str_replace(':'.$d_key, $d_val, $url);
        		$url = str_replace('{'.$d_key.'}', $d_val, $url);
        	}
			return $url . '?' . http_build_query($params);
		}
		
		# 如果没有找到就生成原始的url
		return url($action_name , $params);
	}
	
}

 上面是真正的实现代码

 

下面是调用代码

<?php
/**
 * 站点静态化操作
 * 
 * /static/page/article-php-json_encode.html
 * 
 * 
 */
class Action_Static extends BaseAction 
{
	
	protected function _validate_input()
    {	
    	$engine = $this->app->tool('pagestatic');    	
    	$accessor = $engine->getAccessor();
    	
    	$this->pid = $_GET[$accessor];// page 标识
    	
    	if ( !empty($this->pid) && strlen($this->pid) < 230 )
    	{
    		// 为什么不在此处直接读缓存? 目的是实现未在配置文件中定义的过期缓存全部设为失效
    		
    		$this->pparams = (array) $engine->parsing($this->pid);// page 参数
    		
    		if ( !empty($this->pparams) )
    		{
    			return true;
    		}
    		
    	}
    	
        return false;
    }
    
    /**
     * 请求前对数据进行验证失败时调用此方法
     */
    protected function _on_validate_input_failed()
    {
    	// 记录错误日志(将 pid 记录到错误日志中)
    	
    	
    	// 跳转到首页
    	redirect( url(Config::get('app.default_action','index')) );
    }
    
    
	function execute()
	{
		$cached = val($this->pparams,'nocache',FALSE);
		
		dump($this->pparams,$this->pid);
		
		dump( $this->app->tool('pagestatic')->psurl('core/show',array(
			'id' => '449211678',
			'name' => 'kenxu',
			'age' => '29',			
//			'blog' => 'http://vb2005xu.iteye.com',			
		)) );
	}
}

 

输出结果如下:

http://sfken.xu/static/page/admin.html 写道
admin.html :
Array
(
[action] => admin/index
[nocache] => 1
[params] => Array
(
)

)

core-{id}-{name}.html

core-449211678-kenxu.html?age=29

 

http://sfken.xu/static/page/core-12306-tianchao.html 写道
core-12306-tianchao.html :
Array
(
[action] => core/show
[nocache] => 1
[params] => Array
(
[id] => 12306
[name] => tianchao
)

)

core-{id}-{name}.html

core-449211678-kenxu.html?age=29

 

在我当前的设计中 此路由功能只能算是一个工具类,用于实现 伪静态/或者页缓存用的,功能上只支持指定action的操作,如果诸位有需要,此处就算我 抛砖引玉了....

 

代码很少,也就不一一解释了

   发表时间:2013-06-23  
我现在是扫描目录文件。将方法和class的annoation拿出来作为路由使用的。挺方便的。不用去维护一个大的路由数组了。呵呵。
6 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics