3

我正在使用 zend 框架构建应用程序。

问题是,如何在非 REST 应用程序中使用 Zend_Rest_Controller 的相同控制器逻辑。

例如,假设 twitter 是用 Zend Framework 编写的。他们可能会使用 Zend_Rest_controller 和 Route 作为他们的 API。但是,他们会为他们的网站使用什么(显然使用相同的 API 逻辑)?他们会编写一个简单地触发 REST 请求的全新应用程序吗?是不是超载了。

[编辑]
如果 Web 应用程序通过某些 http_client 类调用 API 来获取数据,则会向服务器发出另一个请求(这会导致性能下降并减慢响应速度)。我不想发出另一个请求,也不想使用 API 中的相同业务逻辑。

谢谢,
维努

4

2 回答 2

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 以便:

  1. 我们可以直接访问请求对象
  2. 我们可以轻松地从任何控制器调用服务

这将在应用程序和数据的实际存储之间发挥作用。

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)

我希望这有帮助。它对我来说效果很好。

于 2011-05-06T18:08:17.437 回答
0

免责声明:我从来没有这样做过,我不知道它有多可行。

由于 Zend_Rest_Controller 扩展了 Zend_Controller_Action,现在除了一些抽象方法之外,还有真正的特定于 rest 的逻辑,你可以让你的网站控制器扩展 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 action helper 为您的 rest 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;
}

快乐黑客!

于 2011-04-29T12:42:02.050 回答