文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Zend_Controller_Action 之 使用技巧(1.0)

Zend_Controller_Action 之 使用技巧(1.0)

时间:2007-08-21  来源:manbuzhe0301

摘自 PHPChina.com qqinxl 网友的帖子,再次向原作者表示感谢. Zend_Controller 作为ZF实现MVC模式的重要组成部分, 若想很好的应用ZF, 控制器部分有很多地方需要花些时间学习. 我觉得下面是一些不错的 ZF 使用技巧, 所以把它们贴在这里,以供日后查看. 也许有些地方表达的不是很精确,但基本纲领领会即可.   1、验证问题。
2、编码转换
3、相同的Controller指向不同的View
4、_redirect函数重构
5、baseUrl的问题

我们都知道,在Zend_Controller_Action里,任何一个请求,都是controller/action构成;而任何一个请求的执行顺序都是init() preDispatch() xxAction() postDispatch()
利用这个,我们可以做很多事情。

1、验证问题。
其实,这个实例大家可以在Getting Started with Zend_Auth by Rob Allen (English)  里找到。当然,英文资料里只是简单实现,很多功能我们可以再扩展。
一个复杂的验证问题是不同页面可能要求验证对象不同。
比如A页面不需要验证。B页面必须登陆用户才能显示;而C必须登陆管理员才能显示。

通过Zend_Controller_Action 继承重构,就可以解决这个问题。

很明显,不需要验证的A页面,我们可以直接直接继承Zend_Controller_Action ,或者写一个MyControllerAction 继承于Zend_Controller_Action,但不增加验证代码。

[复制PHP代码] [ - ] PHP代码如下: abstract class MyControllerAction extends  Zend_Controller_Action {
}


而B页面和C页面,我们可以通过上面说的,每一个C/A 必须经过init()和preDispatch()原则,进行验证。

[复制PHP代码] [ - ] PHP代码如下: abstract class MyControllerAction_User extends MyControllerAction {
//截取部分代码
public function init(){
  parent::init();
  //通过一个模块取得登陆数据
  $authMoudle = Moudle_Auth::getInstance();
  $this->_loginUser = $authMoudle->isLogin(Object_User::User );
  $this->view->loginUser = $this->_loginUser;
}
public function preDispatch(){
  //这里判断是否存在该用户,如果不存在跳出
  if (empty($this->_loginUser)) {   
     if(Mobile::isMobile()){
      $this->_redirect('/auth/ageover');
     }else{
      $this->_redirect('/auth/login');
     }
  }
}
}


通过这个方法,还可以控制那些Controller需要验证,那些不需要验证。

还可以写一个MyControllerAction_Admin用来验证其他类用户,控制C页面的显示。

[复制PHP代码] [ - ] PHP代码如下: //截取部分代码
abstract class MyControllerAction_Admin extends  MyControllerAction {
public function init(){
  parent::init();
  $authMoudle = Moudle_Auth::getInstance();
  //这里就变成验证管理员身份
  $this->_loginAdmin = $authMoudle->isLogin(Object_User::Admin );
  $this->view->loginAdmin = $this->_loginAdmin;
}
public function preDispatch(){
  if (empty($this->_loginAdmin)) {   
       $this->_redirect('/admin/auth/login');
    }
}
}


这样我们的Controller文件可能这样写:

[复制PHP代码] [ - ] PHP代码如下: class AController extends MyControllerAction{
//不需要验证
}
class BController extends MyControllerAction_User{
//验证用户
}
class CdviceController extends MyControllerAction_Admin{
//验证管理员
}


当然,我们再利用Zend_Controller_Front,可以构造出更丰富的逻辑层次

[复制PHP代码] [ - ] PHP代码如下: $frontController->setControllerDirectory(array(
'default' => './application/controllers',
'admin' => './application/admin/controllers',
));


2、编码转换
很多项目数据库保存数据使用UTF-8,而页面显示使用另外一个编码。
我的项目就存在这个问题,页面是SJIS码。数据库等交换保存的全部是UTF-8码。

一个很简单的实现办法就是重构Zend_Controller_Action中的render()方法。注意不是Zend_View里的render()。
大家应该在Controller中几乎每个Action最后一句都是$this->render()。我们就是通过控制这个视图显示,达到编码转换。

[复制PHP代码] [ - ] PHP代码如下: //第四个参数是为ajax设置的。我利用的prototype.js,取得数据自动转为当前页面码,所以不需要提前转换
public function render($action = null, $name = null, $noController = false,$ajax = false)
{
  $view   = $this->initView();
  $script = $this->getViewScript($action, $noController);
  if($ajax){
   $this->getResponse()->appendBody($view->render($script),$name);
  }else{
   $this->getResponse()->appendBody(mb_convert_encoding($view->render($script), "SJIS",'UTF-8'),$name);
  }
}


既然取数据显示到页面需要Utf-8转到SJIS,那么页面取得$_GET或者$_POST也是需要SJIS转到UTF-8才能保存到数据库,或者其他操作的。
因此需要再增加以下两个函数用来获取用户提交的$_GET或者$_POST

[复制PHP代码] [ - ] PHP代码如下: public function getUtfParam($key){
  try{
   $_paras = $this->getRequest()->getParam($key);
   if(!empty($_paras) and is_string($_paras)){
    $_paras = mb_convert_encoding($_paras,'UTF-8', "SJIS,JIS,sjis-win");
   }
   return $_paras;
  }catch (Exception $e){
   throw $e;
  }
}
public function getUtfPost($key){
  try{
   if($this->getRequest()->isPost()){
    $filter = new Zend_Filter_StripTags();
    $value= $filter->filter($this->getRequest()->getPost($key));
    $value = trim($value);
    if(!empty($value) and is_string($value)){
     $value = mb_convert_encoding($value,'UTF-8', "SJIS,JIS,sjis-win");
    }
    return $value;
   }else{
    return null;
   }
  }catch (Exception $e){
   throw $e;
  }
}


3、相同的Controller指向不同的View
同时开发手机Web和Pc Web的时候,我们都知道手机界面和Pc界面差异很大。
一般情况下几乎完全分离。
但是,实际上我们的服务器端数据确实几乎一样的。
比如,用户请求一个Url http://localhost/user/show/id/111 显示id=111的用户信息
服务器端,也就是我们的controller取得数据一样,但是客户端显示的html确分Pc版和mobile版

重构重构Zend_Controller_Action中的initView()方法可以提供一个很好的解决方案。

[复制PHP代码] [ - ] PHP代码如下: public function initView()
{
  if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
   return $this->view;
  }
  require_once 'Zend/View/Interface.php';
  if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) {
   return $this->view;
  }

  $request = $this->getRequest();
  $module  = $request->getModuleName();
  $dirs    = $this->getFrontController()->getControllerDirectory();
  if (empty($module) || !isset($dirs[$module])) {
   $module = 'default';
  }
  $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views';
  if (!file_exists($baseDir) || !is_dir($baseDir)) {
   throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")');
  }
  //在这里,我们重新写了[b]$baseDir[/b] ,指向不同目录
if(Mobile::isMobile()){
   $baseDir .= DIRECTORY_SEPARATOR .'mobile';
  }else{
   $baseDir .= DIRECTORY_SEPARATOR .'pc';
  }
  require_once 'Zend/View.php';
  $this->view = new Zend_View(array('basePath' => $baseDir));
  return $this->view;
}


这时候目录结构应该是这样的:

[复制PHP代码] [ - ] PHP代码如下: /application
    /controllers
    /models
    /views
       /mobile
            /filters
            /helpers
            /scripts
       /pc
            /filters
            /helpers
            /scripts


在views结构下,可以分离为/mobile和/pc两个目录;而两个目录的数据受同一个controller控制。

其实,这个应用不一定手机版Pc版。我们可以在这里控制不同的View版本,比如:

[复制PHP代码] [ - ] PHP代码如下: if(Version::isVersion('1.0')){
   $baseDir .= DIRECTORY_SEPARATOR .'version1';
}elseif(Version::isVersion('2.0')){
  $baseDir .= DIRECTORY_SEPARATOR .'version2';
}else{
   $baseDir .= DIRECTORY_SEPARATOR .'version-test';
  }


4、_redirect函数重构
重构是因为$this->_redirect('user/show');竟然出现错误。(1.0Rc3版本测试结果)
正确的写法是$this->_redirect('/user/show');
因此重写_redirect函数。同时增加session id,支持不支持cookie的浏览器。

[复制PHP代码] [ - ] PHP代码如下: protected function _redirect($url, array $options = array()){
  if(substr($url,0,strlen('/')) === '/'){
   $url = trim($url);
  }else{
   $url = '/'.trim($url);
  }
  $url = $url.'?'.SID;
  parent::_redirect($url,$options);
}


5、baseUrl的问题
这个问题也许有更好的解决办法。
在Rob Allen 的教材里,其实有一个bug。如果url写成http://localhost/zf-tutorials/index.php 的话,css不能正确取得。
其实这个baseUrl 可以重写的。

[复制PHP代码] [ - ] PHP代码如下: protected function _init(){
  $url = $this->_request->getBaseUrl();
  $this->_baseUrl = (basename($url)=='index.php')?dirname($url):$url;
  $this->view->baseUrl = $this->_baseUrl;
}


项目缘故,以上重构是zf版本0.9时候开始写的。经测试兼容1.0。
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载