主页 > PHP | WEB开发 > StBlog中的类似TP的标签库功能的小插件

StBlog中的类似TP的标签库功能的小插件

2010 年 12 月 01 日 没有评论

在一般博客的程序中基本的样式好像就是一边是内容板块,一边是什么分类的板块!像这样子的样式的话,我们在切换整个页面的时候其实变换的是内容板块的内容,而另一边的分类板块是不变的!这样子就要求我们在写程序的时候要注意点了,要使用恰当的方法了!之前在TP中我用的是TP的标签库功能实现了这么一个功能,现在在CI 中,今天看到了StBlog实现的方法。过程如下:
首先我们打开右边板块的试图文件,一下是部分代码:

<h5>日志分类</h5>
 <ul>
     <?php $this->plugin->trigger('Widget::Categories', '<li><a href="{permalink}" title="{description}">{title} [{count}]</a></li>');?>
 </ul>
    
    <h5>最新日志</h5>
 <ul class="post_list">
        <?php $this->plugin->trigger('Widget::Posts::Recent', '<li><a href="{permalink}" title="{title}">{title}</a></li>');?>
 </ul>
    
    <h5>最新评论</h5>
 <ul class="recent_comments">
     <?php $this->plugin->trigger('Widget::Comments::Recent', '<li><a href="{permalink}" title="{parent_post_desc}">{title}: </a><p>{content}</p></li>', 50, '...');?>
 </ul>
 
 <h5>日志归档</h5>
 <ul>
     <?php $this->plugin->trigger('Widget::Posts::Archive', '<li><a href="{permalink}">{title} [{count}]</a></li>', 'month', 'Y年m月');?>
 </ul>

看着这些代码,我们能够直接看懂的好像就是

$this->plugin->trigger()

很明显这是调用了plugin这么一个类文件,我们先找到这个类文件。
其实一看这个类就知道了,一旦这个被加载,是要执行很多操作的,我们先来看构造函数:

public function __construct()
    {
        /** 获取CI句柄 **/
		$this->_CI = & get_instance();
		
		$plugins = $this->_CI->utility->get_active_plugins();
		//print_r($plugins);
		if($plugins && is_array($plugins))
		{
			foreach($plugins as $plugin)
			{
				$plugin_dir = $plugin['directory'] . '/' . ucfirst($plugin['directory']) . '.php';
				
				$path = FCPATH . ST_PLUGINS_DIR . '/' . $plugin_dir;
				
				/** 仅能识别"插件目录/插件/插件.php"目录下的插件 */
				if (preg_match("/^[\w\-\/]+\.php$/", $plugin_dir) && file_exists($path))
				{	
					//加载每一个小功能插件
					include_once($path);

					$class = ucfirst($plugin['directory']);
					
					if (class_exists($class)) 
					{
						/** 初始化插件 */
						//初始化时要调用相应类文件的初始函数(也就是条用了本文件的register函数)
						new $class($this);//传递当前对象
					}
				}
			}
		}

先来分析这个构造函数,

$plugins = $this->_CI->utility->get_active_plugins();

这句话的功能是:从数据库中读取激活的插件名称,因为所有的插件是否激活都是通过后台写进数据库的!通过这个函数可以获取数据库中所有已经激活的插件,至于这个函数 可以去看看utility类文件里面是怎么处理的!
获取的变量$plugins是一个二维数组!接下来遍历这个二维数组,通过索引directory获取的插件的名称,然后再生成相关的路径和文件名,此后在通过PHP的系统函数include_once()来加载这些插件,这些插件放在系统根目录中的st_plugins文件夹下面。其实这个目录路径是可以更改的!这个目录下面每一个文件夹里面就是一个插件,文件夹的名字就是插件的名字!加载完插件之后,就执行了

new $class($this);//传递当前对象

初始化插件!这个初始化是在循环里面,因此只要是在数据库中被激活的插件在这里都会被初始化操作!其实所有的插件的初始化函数都是一样的,只是插件的钩子(即register函数的第一个参数)不一样罢了,代码如下:

public function __construct(&$plugin)
	{
		$plugin->register('Widget::Comments::Recent', $this, 'show_recent_comments');
		
		$this->_CI = &get_instance();
	}

看到该构造函数里面的变量了吗?其实他是个对象!其实这种写法和下面的这种写法是等效的:

$ci = &get_instance();
		$ci->load->libarary('plugin');
		$ci->plugin->register('Widget::Posts::Recent', $this, 'show_recent_posts');

还要注意的一点就是其中的第二个参数和滴三个参数,第二个参数是当前类的一个对象,第三个参数是当前类中的一个方法,这个方法在后面的操作中会被自动的调用!
这里调用了plugin类中的register方法,我们在返回找到这个方法:

[]public function register($hook, &$reference, $method)
	{
		//通过对象获取类的名称
		$key = get_class($reference).'->'.$method;		//返回一个字符串如:Related_posts->show_related_posts
		//$reference为对应的对象,$method为该对象内的一个方法
		$this->_listeners[$hook][$key] = array(&$reference, $method);
		
		log_message('debug', "$hook Registered: $key");
	}

这个方法的功能是将要使用的插件放在一个指定索引和格式的数组中($this->_listeners[$hook][$key]);
上面讲的就是在系统初始化的时候执行的
接下来我们看视图文件,它是调用了plugin类中trigger方法:

public function trigger($hook)
	{
		$result = '';
		//判断钩子是否存在
		if($this->check_hook_exist($hook))
		{
			foreach ($this->_listeners[$hook] as $listener)
			{
				$class  = & $listener[0];		//对象名
				$method = $listener[1];			//方法名
				
				if(method_exists($class, $method))
				{
					$args = array_slice(func_get_args(), 1);//取从第一个开始(除第一个)到最后一个之间的变量
					//调用用户自定义的方法/函数
					//print_r($args);
					$result = call_user_func_array(array($class, $method), $args);
				}
			}
		}
		
		log_message('debug', "Hook Triggerred: $hook");
		
		return $result;
	}

	/**
	 * 检查钩子是否存在
	 * @param string $hook 钩子的名称
	 * @return array
	 */
	public function check_hook_exist($hook)
	{
		if(isset($this->_listeners[$hook]) && is_array($this->_listeners[$hook]) && count($this->_listeners[$hook]) > 0)
		{
			return TRUE;
		}
		
		return FALSE;
	}

这个函数是在加载页面的时候被执行的。其他的就不用多说了,我们只要来看看循环里面的判断部分:
首先判断对象中是否存在该方法 这是肯定的 因为这两个都是从插件类文件中传过来的。之后的获取参数并处理参数部分,
通过程序来看我们只需要获取除了第一个参数以外的全部参数。这是为什么呢?因为第一个参数是插件的钩子,没有任何意义的!因此$args变量是一个数组!我们在通过call_user_func_array()函数来使插件类的对象调用指定的方法(show_recent_posts()),
这个方法在每一个插件中都有,是用来处理数据,我们哪一个插件来说明:
如显示最新日志的:

public function show_recent_posts($format)
	{
		//变量$format是一个html的字符串,其中的一些需要更改的值用{}扩起来了
		/** 输出格式为空?*/
		if(empty($format)) return;
		
		/** 输出多少条? */
		$list_size = setting_item('posts_list_size');
		$list_size = ($list_size && is_numeric($list_size)) ? intval($list_size) : 10;
		
		$posts = $this->_CI->stcache->get('Widget::Posts::Recent');	//判断是否有相应的缓存数据
		
		if(FALSE == $posts)
		{
			$posts = $posts = $this->_CI->db->select('slug, title')
				 ->from('posts')
        		 ->where('type', 'post')
        		 ->where('status', 'publish')
        		 ->orderby('created', 'DESC')
        		 ->limit($list_size)
        		 ->offset(0)
        		 ->get()
        		 ->result();
        
        	$this->_CI->stcache->set('Widget::Posts::Recent', $posts);	//放入缓存
		}
				
		if($posts)
		{
			foreach($posts as $post)
			{
				$wildcards = array('{permalink}', '{title}');
				
				$replaces = array(site_url('posts/'. $post->slug), $post->title);
				
				echo str_replace($wildcards, $replaces, $format) . "\r\n";   //将指定的字符进行替换成我们需要的数据
			}	
		
		}		
		
	}

通过这样子调用,到最后echo一下 就能把数据库中相应的数据输出到我们调用plugin中的trigger方法的地方

($this->plugin->trigger())

!而且不管在哪个页面都是可以直接调用的

Tags: StBlog

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>