说说Yaf Plugins的使用

关于Yaf Plugins的介绍资料都比较简单,介绍请看文档,下面说说使用的实例。

plugin 的路径位于 application/plugins/


一、验证登录

由于不是所有的控制器都需要验证是否登录,在此选择 routerShutdown 路由完成后对具体访问的控制器作是否登录的判断,在 Bootstrap 中注册一个插件:

class Bootstrap extends Yaf_Bootstrap_Abstract
{
	public function _initPlugins(Yaf_Dispatcher $dispatcher)
    {
        $dispatcher->registerPlugin(new PublicblockPlugin());
    }
}

新建一个 Publicblock 文件 application/plugins/Publicblock.php :

class PublicblockPlugin extends Yaf_Plugin_Abstract
{
	/**
     * 是否登录
     */
	public function routerShutdown(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response)
    {
		$curModule = ucfirst(strtolower($request->module));
        $curController = ucfirst(strtolower($request->controller));
		//这里区分了 module, 也可直接使用 $curModule == 'Index',如果没有设置 module 可取消判断
		if( $curModule == ucfirst($config->application->dispatcher->defaultModule) ){
			$checkLogin = array('Apply', 'User'); //需要验证登录的controller
			$freeAction = array('payreturn', 'paynotify'); //如果验证的 Controller 中有无需验证登录的 action
			if(in_array($curController, $checkLogin)){
				//ucenter 的验证方式
				$userInfo = isset($_COOKIE['site_author']) ? UTools::getUserLoginStatus($_COOKIE['site_author']) : array();
				//如果要区分Ajax, $request->isXmlHttpRequest() 在此不生效
				if(!isset($userInfo['uid']) && !in_array($request->action, $freeAction)){
					$ajaxAction = array('submit'); //Ajax 请求的 Action
					if (in_array($request->action, $ajaxAction)) {
                        CTools::ajaxReturn(0, '请您先登录');
                    }else{
						header('Location: http://localhost/logging.php');
						exit;
					}
				}
			}
		}
	}
}


二、将 Layout 实例化移出 Bootstrap 在Plugin中实现,并支持页面 TDK 的方式:

在 Bootstrap 中的 _initLayout

public function _initLayout(Yaf_Dispatcher $dispatcher)
{
	$layout = new Layout(Yaf_Application::app()->getConfig()->application->layout->directory);
	$dispatcher->setView($layout);
}

现将上面的方法注释,去 Plugin 中实现,并能根据不同的 module 实现不同的 layout:

class PublicblockPlugin extends Yaf_Plugin_Abstract
{
    public $layout;
	
	
	public function dispatchLoopStartup(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response)
    {
        try {
            $config = Yaf_Application::app()->getConfig();
            $modulesArr = Yaf_Application::app()->getModules();
            $layoutPath = $config->application->layout->directory;
			//根据 module 设定 layout
            if(in_array($request->module, $modulesArr) && $request->module != ucfirst($config->application->dispatcher->defaultModule)){
                $layoutPath = str_replace('views', 'modules/'. $request->module .'/views', $layoutPath);
            }
            $this->layout = new Layout($layoutPath);
			//如果需要设置 SEO信息, 避免改动各页面相关的控制器
            //$this->_seoSets($request, $response);
            Yaf_Application::app()->getDispatcher()->setView($this->layout);
        } catch (Exception $e) {
			//异常处理
            CTools::processException($e);
        }
    }
	
	
	/**
     * SEO TDK
     */
    protected function _seoSets($request, $response)
    {
		//Key: Controller_Action
		$_seoRule = array(
            'Index_index' => array(
                    'title' => '【标题】文字_%city站',
                    'keywords' => '关键词',
                    'description' => '文字_%city站'
            ),
            'List_index' => array(
                    'title' => '【标题】第%page页_%city站',
                    'keywords' => '关键词',
                    'description' => '文字_%city站'
            )
		);
		
		try {
		
			//如果开启了重写需处理一下
			$curAction = strpos($request->action, '.html') ? str_replace('.html', '', $request->action) : $request->action;
            $curModule = ucfirst(strtolower($request->module));
            $curController = ucfirst(strtolower($request->controller));
			if($curModule == 'Index'){
				//定位城市
                $cityInfo = CTools::getCurrentCity();
                $cityName = isset($cityInfo['cityName']) ? str_replace('市', '', $cityInfo['cityName']) : '北京';
				$_seoVal = array();
                $_accessKey = $curController .'_'. $curAction;
				if(isset($_seoRule[$_accessKey])){
					$_rule = $_seoRule[$_accessKey];
					/* TDK 参数, CUrl 见前面的文章介绍 */
                    if(CUrl::isOpenRewrite()){
                        $page = (int) $request->getParam('page');//页码
                    }else{
                        $page = (int) $request->getQuery('page');//页码
                    }
					$pageStr = $page > 0 ? '_第'. $page .'页' : '';
					foreach ($_rule as $key=>$val)
					{
						//使用 sprintf 不大好处理,故使用 %变量名
						$_seoVal[$key] = str_replace(array('%page', '%city'), array($pageStr, $cityName), $val);
					}
				}
				
				$_seo = CTools::getSeoCode($_seoVal);
				//assign 
				$this->layout->assign('_seo', $_seo);
			}
		
		} catch (Exception $e) {
            CTools::processException($e);
        }
	}
	
}


设置好了 TDK 后在模板(views/layouts )中添加

<!DOCTYPE html>
<html>
<head>
	<?=$this->_seo ?>
</head>

如果为了避免部分 Action 未设置 TDK 而影响页面需使用默认值时,在主控制器中设置默认值:

class ApplicationController extends Yaf_Controller_Abstract
{
	public function init()
    {
		//...
		
		//Set SEO
        if(!$this->getView()->getVar('_seo'))
            $this->getView()->_seo = CTools::getSeoCode(array('title' => 'site'));
	}
}

三、Rewrite

在项目开发完成,链接已经 Rewrite 后,SEO 要求在域名后面接城市字母简拼为前缀,即将 http://localhost/index.html 改成 http://localhost/bj/index.html ,如果改 Rewrite 规则麻烦,还得各种测试,于是利用 Plugin 实现,在 Bootstrap 中注册一个插件:

public function _initPlugins(Yaf_Dispatcher $dispatcher)
{
	$dispatcher->registerPlugin(new RewritePlugin()); //注册 RewritePlugin
	
	$dispatcher->registerPlugin(new PublicblockPlugin());
}

Rewrite.php

<?php
/**
 * 链接处理
 * 解决以城市拼音 为开头 被当做 控制器名解析
 *  /bj/index.html
 * 
 * @author Shixue
 * @date 2017-11-10
 * Yaf version 2.3.5
 */
class RewritePlugin extends Yaf_Plugin_Abstract 
{
    /**
     * 路由之前处理
     * HTTP/1.1 200 OK
     * HTTP/1.1 301 Moved Permanently
     * HTTP/1.1 404 Not Found
     */
    public function routerStartup(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response)
    {
        $uri = addslashes($request->getServer("REQUEST_URI"));
        list($uriLink) = explode('#', $uri);
        list($uriUrl) = explode('?', $uriLink);
        $urlArr = explode('/', trim($uriUrl, '/'));
        $city = $urlArr ? strtolower(array_shift($urlArr)) : '';
        //获取所有城市拼音数据
        $cityData = CTools::getCityPinyin();
        //当前定位的或选择的城市
        $cityInfo = CTools::getCurrentCity();
        if(empty($city) || !array_key_exists($city, $cityData) ){
            $notCity = !$city || !preg_match('/(Ajax|pay|app|add)/i', $city) ? true : false; //排除 Ajax 和  带 .html
            if($notCity){
                $listname = isset($cityInfo['listname']) && $cityInfo['listname'] ? trim($cityInfo['listname']) : 'bj';
                //header("HTTP/1.1 301 Moved Permanently");
                header('Location: /'. $listname . $request->getServer("REQUEST_URI"));
                exit;
            }else{
                array_unshift($urlArr, $city);
            }
        }else{
            
            //设置城市ID 和 listname
            //$currentCityId = (int) $cityData[$city];
            //$request->setParam('listname', $city);
            //$request->setParam('cityId', $currentCityId);
			//var_dump($request->getParam('listname'));exit;
        }
        
        $newUri = '/'. implode('/', $urlArr);
        $request -> setRequestUri($newUri);
    }
}

以上是实际中使用 Plugin 解决的方法。


Layout 中自定义了一个 getVar() 方法,/application/library/Layout.php 文件如下:

<?php
/**
 * Layout class used for render layouts and views.
 *
 * Layout class allows to use of a base layout skeleton and render views inside 
 * this layout template.
 * The concept is to not render and display the view template directly but storing it
 * in {@link $content} property. Then will render the skeleton layout and 
 * pass the {@link $content} property to it.
 * <code>
 *  application/views/layouts/front.phtml
 *
 *  <html>
 *      <head>
 *          <title><?php echo $title ?></title>
 *      </head>
 *      <body>
 *          <?= $_content_ // This is where your view from each action 
 *          will be displayed ?>
 *      </body>
 *  </html>
 * </code>
 * 
 * If no layout is defined then returns the renderd action view template.
 *
 * Also allows to set variable to views and access them from the base 
 * skeleton layout. In above layout $title variable is set to title tag.
 * Then in a view template we can set the value for $title variable.
 * <code>
 *  application/views/index/index.phtml
 *
 *  <?php $this->title = "Index Action" ?>
 *  <h1>Index Action</h1>
 * </code>
 *
 * @author Andreas Kollaros <mail@dot.com>
 *
 */
class Layout implements Yaf_View_Interface
{

    /**
     * The template engine to render views and layout templates.
     *
     * Default engine is Yaf\View\Simple
     *
     * @var Yaf\View\Simple
     */
    public $engine;

    /**
     * Options to be passed to template engine.
     *
     * @var array
     */
    protected $options=array();

    /**
     *
     */
    protected $layout_path;

    /**
     * The name of layout file without extension.
     *
     * @var string
     */
    protected $layout;

    /**
     * Handles the rendered action view data.
     *
     * @var string
     */
    protected $content;

    /**
     * Array with assigned template variables.
     *
     * @var array
     */
    protected $tpl_vars = array();

    /**
     * Template directory.
     *
     * @var string
     */
    protected $tpl_dir;

    /**
     * Constructor
     *
     * @param array $options key/value pair of options to be assigned to 
     *                       template engine.
     *
     * @return void
     */
    public function __construct($path, $options=array()) 
    {
        $this->layout_path = $path;
        $this->options = $options;
    }

    /**
     * Return the instance of a template engine. 
     *
     * @return Yaf\View\Simple
     */
    protected function engine()
    {
        $this->engine =  $this->engine ?  $this->engine : new Yaf_View_Simple(
            $this->tpl_dir, 
            $this->options
        );

        return $this->engine;
    }

    /**
     * Create engine instance and set the path of views and layout templates.
     *
     * Layout path is set by default to layout directory inside views path.
     *
     * @param string $path The directory to set as the path.
     *
     * @return void
     */
    public function setScriptPath($path)
    {
        if (is_readable($path)) {
            $this->tpl_dir = $path;
            $this->engine()->setScriptPath($path);

            // Overwirte layouts path by setting it where views path is.
            // This will force layout in modules to be placed in 
            // modules/views/layouts directory
            $this->layout_path = $path . "/layouts";

            return true;
        }

        throw new Exception("Invalid path: {$path}");
    }

    /**
     * Getter method for views path.
     *
     * @return string
     */
    public function getScriptPath()
    {
        return $this->engine()->getScriptPath();
    }

    /**
     * Setter for Layout::layout variable
     *
     * @param string $name the name of layout file without extension.
     *
     * @return void
     */
    public function setLayout($name)
    {
        $this->layout = $name;
    }

    /**
     * Getter for Layout::layout variable
     *
     * @return string the name of layout file without extension
     */
    public function getLayout()
    {
        return $this->layout;
    }


    public function setLayoutPath($path)
    {
        $this->layout_path = $path;
    }

    /**
     * Get full layout path with filename and extension.
     *
     * @return string 
     */
    public function getLayoutPath()
    {
        $config = Yaf_Application::app()->getConfig()->get('application');
        return $this->layout_path . "/" . $this->layout . ".{$config->view->ext}";
    }

    /**
     * Assign a variable to the template
     *
     * @param string $name  The variable name.
     * @param mixed  $value The variable value.
     *
     * @return void
     */
    public function __set($name, $value)
    {
        $this->assign($name, $value);
    }

    /**
     * Allows testing with empty() and isset() to work
     *
     * @param string $name
     *
     * @return boolean
     */
    public function __isset($name)
    {
        return (null !== $this->engine()->$name);
    }

    /**
     * Allows unset() on object properties to work
     *
     * @param string $name
     *
     * @return void
     */
    public function __unset($name)
    {
        $this->engine()->clear($name);
    }

    /**
     * Assign variables to the template
     *
     * Allows setting a specific key to the specified value, OR passing
     * an array of key => value pairs to set en masse.
     *
     * @see __set()
     * 
     * @param string|array $name  The assignment strategy to use (key or
     *                            array of key => value pairs)
     * @param mixed        $value (Optional) If assigning a named variable,
     *                            use this as the value.
     *
     * @return void
     */
    public function assign($name, $value = null) 
    {

        $this->tpl_vars[$name] = $value;

        $this->engine()->assign($name, $value);
    }
    
    public function getVar($name)
    {
        return isset($this->tpl_vars[$name]) ? $this->tpl_vars[$name] : null;
    }

    /**
     * Assign variables by reference to the template
     *
     */
    public function assignRef($name, &$value)
    {
        $this->tpl_vars[$name] = $value;

        $this->engine()->assignRef($name, $value);
    }

    /**
     * Clear all assigned variables
     *
     * Clears all variables assigned to Yaf\View either via
     * {@link assign()} or property overloading
     * ({@link __get()}/{@link __set()}).
     *
     * @return void
     */
    public function clearVars() {
        $this->tpl_vars = array();
        $this->engine()->clear();
    }

    /**
     * Processes a view and returns the output.
     *
     * This method called once from controller to render the given view.
     * So render the view at $this->content property and then render the 
     * layout template.
     *
     * @param string $tpl      The template to process.
     * @param array  $tpl_vars Additional variables to be assigned to template.
     *
     * @return string The view or layout template output.
     */
    public function render($tpl, $tpl_vars=array()) {

        $tpl_vars = array_merge($this->tpl_vars, $tpl_vars);

        $this->content = $this->engine()->render($tpl, $tpl_vars);

        // if no layout is defined,
        // return the rendered view template
        if (null == $this->layout) {

            return $this->content;
        }

        // If we assign some variables into view template, then maybe we need 
        // them to layout view.
        // Hack??
        // Get template vars from view via Reflection class and assign them to 
        // layout view
        #$ref = new ReflectionClass($this->engine());
        #$prop = $ref->getProperty('_tpl_vars');
        #$prop->setAccessible(true);
        #$view_vars = $prop->getValue($this->engine());
        #$tpl_vars = array_merge($tpl_vars, $view_vars);
        $tpl_vars['_content_'] = $this->content;

        return $this->engine()->render(
            $this->getLayoutPath(), 
            $tpl_vars
        );
    }

    /**
     * Directly display the constens of a view / layout template.
     *
     * @param string $tpl      The template to process.
     * @param array  $tpl_vars Additional variables to be assigned to template.
     *
     * @return void
     */
    public function display($tpl, $tpl_vars=array()) {
        echo $this->render($tpl, $tpl_vars);
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值