Action简介
在Action类中可以处理其他输入数据,访问数据库,调用业务逻辑类。本例中我们在Action类中检查用户权限是否可以访问公司报表,调用业务逻辑类查询或更新数据库。
我们通过扩展框架的Action类来实现自己的应用Action类,本例我们使用了一个叫做AbstractBaseAction的抽象类,同样的,这个类也包含了一些通用的逻辑。SalesReportAction类则具体实现了AbstractBaseAction类,在前面的应用程序对象图中我们可以清楚地看到对象之间的关系。
一个Action类在XML配置文件中如下定义:
<action-mappings>
<action path = "salesReport"
type = "SalesReportAction"
name = "salesReportForm"
validate = "true"
input = "salesReportIndex.tpl"
scope = "request">
<forward name="salesReportSuccess" path="salesReport.tpl" />
<forward name="salesReportFailure" path="salesReportIndex.tpl"/>
</action>
</action-mappings>
各种属性的含义在前面都已经讲过,这里就不在赘述了。
AbstractBaseAction类
下面是删减了的AbstractBaseAction类
class AbstractBaseAction extends Action {
// ----- Instance Variables --------------------------------------------- //
var $log = NULL;
var $actionErrors = NULL;
var $pmr = NULL;
var $locale = NULL;
var $dbConn = NULL;
// ----- Constructor ---------------------------------------------------- //
function AbstractBaseAction() {
$this->log = new PhpMVC_Log();
$this->actionErrors =& new ActionErrors();
$config = 'MyAppResources';
$returnNull = False;
$defaultLocale =& new Locale();
$factory = NULL;
$pmr =& new PropertyMessageResources($factory, $config, $returnNull);
$pmr->setDefaultLocale($defaultLocale);
$this->pmr = $pmr;
}
// ----- Public Methods ------------------------------------------------- //
function execute($mapping, $form, &$request, &$response) {
; // Implement this method in your concrete Action classes
}
}
构造函数
AbsractBaseAction提供了一些通用服务,比如错误或消息字符串处理,类似于前面AbstractBaseForm类。而且,还提供了一个logging类用来记录错误日志。Locale和PropertyMessageResources类在ActionForm章节已经讲过了。
execute()方法
当框架接收到一个请求将会执行相应action的execute()方法,在后面的SalesReportAction类中我们将具体实现该方法。
SalesReportAction类
下面是删减了的SalesReportAction类。这个类通过继承AbstractBaseAction类来多重继承框架的Action类。
class SalesReportAction extends AbstractBaseAction {
// ----- Constructor ---------------------------------------------------- //
function SalesReportAction() {
parent::AbstractBaseAction();
$this->log->setLog('isTraceEnabled' , True);
}
// ----- Public Methods ------------------------------------------------- //
function execute($mapping, $form, &$request, &$response) {
$trace = $this->log->getLog('isTraceEnabled');
if($trace) {
$this->log->trace('Start: SalesReportAction->execute(...)'.
'['.__LINE__.']');
}
$actionErrors =& $this->actionErrors;
$pmr =& $this->pmr;
$locale =& $this->locale;
$username = $request->getParameter('uname');
$password = $request->getParameter('pword');
$group = $request->getParameter('urole');
// SQL as required
$aclCheck = False;
if($group == 'accounts') {
$aclCheck = True;
}
$myForward = NULL;
if($aclCheck == True) {
$myForward = $mapping->findForwardConfig('salesReportSuccess');
$sales = NULL;
$salesReport =& new ReportsBusinessClass();
$sales = $salesReport->getSales($this->dbConn);
$request->setAttribute('FORM_DATA', $sales);
} else {
$myForward = $mapping->findForwardConfig('salesReportFailure');
$msg = $pmr->getMessage($locale, 'report.auth.failed');
$actionErrors->add( 'report_auth_failed', new ActionError($msg) );
$request->setAttribute(Action::getKey('ERROR_KEY'), $actionErrors);
$form->setUserName($username);
$form->setPassWord($password);
$form->setUserRole($group);
$request->setAttribute( 'ACTION_FORM', $form );
}
return $myForward;
}
}
构造函数
当类被实例化时构造函数自动被调用,在本构造函数中我们调用父类的构造函数(parent::AbstractBaseAction())设置通用服务。另外我们可以设置是否记录日志,比如:$this->log->setLog('isTraceEnabled', True)。
execute()方法
在前面我们已经看到框架会根据请求路径找到相应的Action然后调用其execute()方法。
日志
在execute()方法中可以使用logging来记录程序的执行路径,我们能使用如下方法:
$trace = $this->log->getLog('isTraceEnabled');
if($trace) {
$this->log->trace('Start: SalesReportAction->execute(...)'.
'['.__LINE__.']');
}
在程序运行时输出可能是:Trace: Start: SalesReportAction->execute(...)[85]
错误对象,属性消息资源和现场
$actionErrors =& $this->actionErrors;
$pmr =& $this->pmr;
$locale =& $this->locale;
其用法类似于ActionForm。
访问表单域
我们可以得到表单域的值,进一步地执行验证。注意我们已经在ActionForm类中验证了表单域的正确性,因此现在我们可以假设表单域是有效的。
$username = $request->getParameter('uname');
$password = $request->getParameter('pword');
$group = $request->getParameter('urole');
检查用户权限
在这个阶段我们可以检查用户是否有权限去访问资源,我们能查询数据库,或者使用专门的认证与权限管理系统比如phpLIB::auth或PEAR::LiveUser进行验证。在本例中我们仅仅是检查urole表单域是否设置为'accounts',如下:
$aclCheck = False;
if($group == 'accounts') {
$aclCheck = True;
}
假如用户有正确的权限,我们就设置访问控制列表(ACL)变量($aclCheck)为True,指示用户可以访问我们的资源。
业务逻辑
现在我们可以访问业务逻辑类ReportsBusinessClass,因为ACL变量($aclCheck)已经置True;
if($aclCheck == True) {
...
接下来,我们得到一个名为'salesReportSuccess'的Forward配置对象:
$myForward = $mapping->findForwardConfig('salesReportSuccess')
对应着phpmvc-config.xml文件的action节点中的forward元素
<forward name="salesReportSuccess" path="salesReport.tpl" />。
现在,我们为业务类创建一个新的实例
$salesReport =& new ReportsBusinessClass();
并调用其getSales()方法:
$sales = $salesReport->getSales($this->dbConn)。
业务逻辑类返回一个$sales对象包含了几个类变量,在后面的报表模板中将访问它。
class Sales {
var $salesNorth;
var $salesSouth;
...
}
注意:为了降低耦合提高代码可重用性,我们允许为业务逻辑类指定对象作为参数。在实例中我们便把数据库对象参照赋给了业务对象方法,这种设计可以让我们在其他应用程序中重用业务逻辑类。
最终保存$sales对象到request,我们就可以在显示模板中访问这个对象了。
$request->setAttribute('FORM_DATA', $sales);
权限拒绝
假如用户没有通过验证($aclCheck=False),我们便得到一个名为'salesReportFailure'的Forward配置对象:
$myForward = $mapping->findForwardConfig('salesReportFailure');
同样的,这也将查找XML配置文件的action节点中的forward元素
<forward name="salesReportFailure" path="salesReportIndex.tpl"/>;
接下来的任务就是为表单设置适当的错误消息,前面已经讲过PropertyMessageResources和ActionErrors类的用法
$msg = $pmr->getMessage($locale, 'report.auth.failed');
$actionErrors->add( 'report_auth_failed', new ActionError($msg) );
注意,这里我们没有创建可替换参数。
下面,就保存错误对象到request对象中:
$request->setAttribute(Action::getKey('ERROR_KEY'), $actionErrors);
在后面我们可以得到这个错误对象:
$errors = $request->getAttribute( Action::getKey('ERROR_KEY') );
相应的表单域现在也保存到ActionForm对象$form中,
$form->setUserName($username);
$form->setPassWord($password);
$form->setUserRole($group);
同样的,$form对象也被保存到request对象中:
$request->setAttribute( 'ACTION_FORM', $form );
这个对象也可以这样被得到:
$form = $request->getAttribute('ACTION_FORM');
然后,就是返回Forward对象
return $myForward;
接下来,控制器将调用自定义的ActionDispatcher类来进行处理。
发表于 @ 2004年12月31日 08:21:00|评论(loading...)|编辑