【问题标题】:PhalconPHP: content negotiation?PhalconPHP:内容协商?
【发布时间】:2014-09-02 22:30:32
【问题描述】:

Phalcon 是否支持开箱即用的内容协商,还是有一些易于实施的解决方案?我正在搜寻“网”,但没有看到它。

谢谢!

【问题讨论】:

    标签: php phalcon content-negotiation


    【解决方案1】:

    简短的回答是否定的,感谢上帝,否则我们会有另外 100 个错误用于非主要组件:)

    您可以轻松地将现有库(例如 Negotiation)插入 DI,然后在整个应用程序中全局使用。

    $di->setShared('negotiator', function(){
        return new \Negotiation\Negotiator(); 
    });
    
    $bestHeader = $di->getShared('negotiator')->getBest('en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2');
    

    请记住,使用示例中的默认服务器配置(.htaccess / Nginx),静态文件将按原样提供,不会被 Phalcon 拦截。因此,对于来自服务器的服务器文件,最好创建一个单独的控制器/操作来处理它,而不是让所有请求都通过您的应用程序。

    编辑:

    如果只是让您的应用程序能够根据共同的区别(标头、参数、方法)发送 xml 或 json,那么您可以在没有外部框架的情况下轻松完成它。有很多策略,最简单的方法是拦截Dispatcher::dispatch(),在其中决定要返回的内容并相应地配置视图和响应——剩下的工作由 Phalcon 完成。

    /**
     * All controllers must extend the base class and actions must set result to `$this->responseContent` property,
     * that value will be later converted to the appropriate form.
     */
    abstract class AbstractController extends \Phalcon\Mvc\Controller
    {
    
        /**
         * Response content in a common format that can be converted to either json or xml.
         * 
         * @var array
         */
        public $responseContent;
    }
    
    /**
     * New dispatcher checks if the last dispatched controller has `$responseContent` property it will convert it
     * to the right format, disable the view and direcly return the result.
     */
    class Dispatcher extends \Phalcon\Mvc\Dispatcher
    {
    
        /**
         * @inheritdoc
         */
        public function dispatch()
        {
            $result            = parent::dispatch();
            $headerAccept      = $this->request->getHeader('Accept');
            $headerContentType = $this->request->getHeader('Content-Type');
            $lastController    = $this->getLastController();
    
            // If controller is an "alien" or the response content is not provided, just return the original result.
    
            if (!$lastController instanceof AbstractController || !isset($lastController->responseContent)) {
                return $result;
            }
    
            // Decide what content format has been requested and prepare the response. 
    
            if ($headerAccept === 'application/json' && $headerContentType === 'application/json') {
                $response = json_encode($lastController->responseContent);
                $contentType = 'application/json';
            } else {
                $response = your_xml_convertion_method_call($lastController->responseContent);
                $contentType = 'application/xml';
            }
    
            // Disable the view – we are not rendering anything (unless you've already disabled it globally).
    
            $view->disable();
    
            // Prepare the actual response object.
    
            $response = $lastController->response
                ->setContent($response)
                ->setContentType($contentType);
    
            // The returned value must also be set explicitly.
    
            $this->setReturnedValue($response);
    
            return $result;
        }
    }
    
    // In your configuration you must insert the right dispatcher into DI.
    
    $di->setShared('dispatcher', function(){
        return new \The\Above\Dispatcher();
    });
    

    只是认为您可以使用dispatch loop events 实现相同的效果。理论上的解决方案可能看起来更优雅,但我从未尝试过,所以您可能想自己尝试一下。

    【讨论】:

    • 明白了。我认为内容协商 - 特别是格式协商 - 对于 API/微应用程序很重要。谢谢指点。
    • 资产格式或请求格式(html / json)还是你有别的想法?
    • 这取决于你想把事情复杂化到什么程度。如果它只是让您的应用程序能够根据共同的区别(标头、参数、方法)发送 xml 或 json,那么您可以在没有外部框架的情况下轻松完成它。更深入地描述你所拥有的和需要什么,我可能会分享更多的想法。
    • 是的,这正是我想要完成的:“使应用程序能够根据共同的区别 (...) 发送 xml/json”
    • 太棒了。那应该有帮助。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 2015-08-06
    • 2011-02-05
    • 2012-08-13
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    相关资源
    最近更新 更多