PhalconPHP:内容谈判?

时间:2014-09-02 22:30:32

标签: php phalcon content-negotiation

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

谢谢!

1 个答案:

答案 0 :(得分: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实现同样的目标。理论上的解决方案可能看起来更优雅,但我从未尝试过,所以你可能想自己尝试一下。