我正在使用zend框架构建应用程序。
问题是,如何在非REST应用程序中使用Zend_Rest_Controller的相同控制器逻辑。
例如,我们假设twitter是用Zend Framework编写的。他们可能会使用Zend_Rest_controller和Route作为他们的API。但是,他们会为他们的网站使用什么(显然使用相同的API逻辑)?他们会编写一个简单激活REST请求的全新应用程序吗?不是那么过载。
[编辑]
如果Web应用程序通过某个http_client类调用API来获取数据,则会向服务器发出另一个请求(这会导致性能下降并降低响应速度)。我不想提出另一个请求,并希望使用API中的相同业务逻辑。
谢谢,
VENU
答案 0 :(得分:2)
我想出了一个似乎运作良好的模式。它解决了您的所有问题: 这是我提出的缩小版本:
首先我们需要自己的控制器。如果未定义任何操作请求,此控制器将具有服务,其中代理服务的任何操作请求:
abstract class App_Rest_Controller extends Zend_Controller_Action
{
/**
* @var App_Rest_Service_Abstract
*/
protected $_service;
public function __call($methodName, $args)
{
if ('Action' == substr($methodName, -6)) {
$action = substr($methodName, 0, strlen($methodName) - 6);
return $this->_service()->$action();
}
return parent::__call($methodName, $args);
}
}
现在是服务的时候了。我们扩展了Action Helper Abstract,以便:
这将在应用程序和实际存储数据之间进行。
abstract class App_Rest_Service_Abstract extends Zend_Controller_Action_Helper_Abstract
{
/*
* @var App_Rest_Storage_Interface
*/
protected $_storage;
public function __call($methodName, $args)
{
if (!method_exists($this->getStorage(), $methodName)) {
throw new App_Rest_Service_Exception(sprintf('The storage does not have the method "%s"', $methodName));
}
switch ($methodName) {
case 'get':
case 'put':
case 'delete':
//if id param isnot set, throw an exception
if (FALSE === ($id = $this->getRequest()->getParam('id', FALSE))) {
throw new App_Rest_Service_Exception(sprintf('Method "%s" expects an id param, none provided', $methodName));
}
$iterator = $this->getStorage()->$methodName($id, $this->getRequest()->getParams());
break;
case 'index':
case 'post':
default:
//if index, post or not a tradition RESTful request, the function must expect the first and only argument to be an array
$iterator = $this->getStorage()->$methodName($this->getRequest()->getParams());
break;
}
return $this->_getResult($iterator);
}
protected function _getResult($iterator)
{ /*
* write your own, in my case i make a paginator and then
* either return it or send data via the json helper
*
/*
}
现在为界面。这将完成存储,修改和返回数据的实际工作。将它用作界面的美妙之处在于,无论您对模型层使用什么,都可以轻松实现它。我创建了一个抽象存储,它只有一个Zend_Form(用于验证)和一个Zend_Db_Table用于实际数据。但你也可以在任何对象上实现它。
interface App_Rest_Storage_Interface extends Zend_Validate_Interface
{
public function index(array $params = NULL);
public function get($id, array $params = NULL);
public function post(array $params);
public function put($id, array $params);
public function delete($id, array $params);
}
现在在您网站的任何位置进行操作。假设您有“客户”服务。在任何控制器内部,它就像
一样简单$customer = $this->_helper->helper->customers->get(1);
其他任何地方(例如视图助手):
Zend_Controller_Action_HelperBroker::getStaticHelper('customers')->get(1)
我希望这会有所帮助。它对我很有用。
答案 1 :(得分:0)
免责声明:我从未这样做过,我不知道它有多可行。
由于Zend_Rest_Controller扩展了Zend_Controller_Action,现在除了一些抽象方法之外还有真正的休息特定逻辑,你可以让你的网站控制器扩展Rest控制器。例如:
class Web_IndexController extends Rest_IndexController
{
public function IndexAction() {
//do whatever your rest contrller would do
$result = parent::indexAction();
//add website specific specific logic here
}
}
如果您的其他控制器的操作是返回值,例如基于发生的事件的数据库对象或数组,那么您可以使用返回的数据来执行特定于网站的逻辑。
要考虑的一件事是,如果您使用json动作帮助器返回其余api的值,则应该构建一个控制器属性来抑制发送和退出。例如:
class Rest_IndexController extends Zend_Rest_Controller
{
protected $_sendJson = TRUE;
public function IndexAction() {
$this->_helper->json($data, $this->_sendJson);
}
}
class Web_IndexController extends Rest_IndexController
{
protected $_sendJson = FALSE;
}
快乐黑客!