【发布时间】:2012-02-08 10:03:54
【问题描述】:
我已经在 Zend Framework (1.10) 上构建了一个首次运行的 Web 服务,现在我正在寻找方法来重构我的动作控制器中的一些逻辑,以便对我和其他人来说更容易我的团队来扩展和维护服务。
我可以看到哪里有重构的机会,但我不清楚如何采用最佳策略。最好的控制器文档和教程只讨论小规模的应用程序,并没有真正讨论如何抽象出更重复的代码,这些代码会蔓延到更大的范围内。
我们的动作控制器的基本结构是:
- 从请求正文中提取 XML 消息 - 这包括针对特定于操作的 RelaxNG 架构进行验证
- 准备 XML 响应
- 验证请求消息中的数据(无效数据引发异常 - 将消息添加到立即发送的响应中)
- 执行数据库操作(选择/插入/更新/删除)
- 返回操作的成功或失败以及所需的信息
一个简单的例子是这个动作,它根据一组灵活的标准返回供应商列表:
class Api_VendorController extends Lib_Controller_Action
{
public function getDetailsAction()
{
try {
$request = new Lib_XML_Request('1.0');
$request->load($this->getRequest()->getRawBody(), dirname(__FILE__) . '/../resources/xml/relaxng/vendor/getDetails.xml');
} catch (Lib_XML_Request_Exception $e) {
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Vendor/getDetails: Error validating incoming request message', $e);
}
// Elevate as general error
throw new Zend_Controller_Action_Exception($e->getMessage(), 400);
}
$response = new Lib_XML_Response('API/vendor/getDetails');
try {
$criteria = array();
$fields = $request->getElementsByTagName('field');
for ($i = 0; $i < $fields->length; $i++) {
$name = trim($fields->item($i)->attributes->getNamedItem('name')->nodeValue);
if (!isset($criteria[$name])) {
$criteria[$name] = array();
}
$criteria[$name][] = trim($fields->item($i)->childNodes->item(0)->nodeValue);
}
$vendors = $this->_mappers['vendor']->find($criteria);
if (count($vendors) < 1) {
throw new Api_VendorController_Exception('Could not find any vendors matching your criteria');
}
$response->append('success');
foreach ($vendors as $vendor) {
$v = $vendor->toArray();
$response->append('vendor', $v);
}
} catch (Api_VendorController_Exception $e) {
// Send failure message
$error = $response->append('error');
$response->appendChild($error, 'message', $e->getMessage());
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Account/GetDetails: ' . $e->getMessage(), $e);
}
}
echo $response->save();
}
}
那么 - 知道我的控制器中的共性在哪里,什么是重构的最佳策略,同时保持它类似于 Zend 并且还可以使用 PHPUnit 进行测试?
我确实考虑过将更多控制器逻辑抽象到父类 (Lib_Controller_Action) 中,但这使得单元测试更加复杂,在我看来这是错误的。
【问题讨论】:
-
也许将通用性下推到服务/存储库类中?这样的类是可测试的,可以跨控制器使用,并且可以使控制器代码更紧凑。
-
另一种方法是将共性收集到行动助手中。
标签: php model-view-controller zend-framework refactoring