Ajax 根据标题切换渲染,应用程序范围

Ajax 根据标题切换渲染,应用程序范围,ajax,content-type,phalcon,Ajax,Content Type,Phalcon,这是一个有待解决的问题 让我们设想一个显示过滤产品列表的网站页面: 如果我在浏览器中请求/products?foo=bar,我会得到一个包装在版面中的完整页面,该版面包含一个标题,该标题带有一个允许更改搜索标准的表单 如果我将foo值更改为baz并提交表单,它将动态地重新加载结果(例如,使用jQuery$.load()),在Ajax中调用/products?foo=baz 如果我在iPhone应用程序中输入相同的条件,应用程序会向服务器请求/products?foo=bar,服务器会用json对

这是一个有待解决的问题

让我们设想一个显示过滤产品列表的网站页面:

  • 如果我在浏览器中请求
    /products?foo=bar
    ,我会得到一个包装在版面中的完整页面,该版面包含一个标题,该标题带有一个允许更改搜索标准的表单

  • 如果我将
    foo
    值更改为
    baz
    并提交表单,它将动态地重新加载结果(例如,使用jQuery
    $.load()
    ),在Ajax中调用
    /products?foo=baz

  • 如果我在iPhone应用程序中输入相同的条件,应用程序会向服务器请求
    /products?foo=bar
    ,服务器会用json对象进行回复

  • 所有3个调用都引用相同的资源(“产品列表”,资源与REST资源相同),但都需要不同的呈现

  • 在第一种情况下,我需要一个完整的HTML页面(带有布局)
  • 在第二种情况下,我需要一个部分HTML页面(没有布局)
  • 在第三种情况下,我需要一个简单的json响应
  • 此呈现开关可由标题
    X-request-With
    (带或不带布局)和
    Accept
    (html/json)触发

    在Phalcon中,给出的示例可以实现为:

    class ProductsController扩展\Phalcon\Mvc\Controller
    {
    公共函数索引()
    {
    //构建数据
    $products=products::查找(数组)(
    'foo'=>this->request->get('foo')
    ));
    //JSON被识别
    如果($this->request->getBestAccept()=='application/json')
    {
    //JSON呈现(案例3)
    $this->response->setContentType('application/json');
    $this->response->setJsonContent($products);
    $this->view->disable();
    返回$this->response;
    }
    //否则,默认为HTML
    其他的
    {
    //向视图传递数据
    $this->view->products=$products;
    //Ajax调用被识别
    如果($this->request->isAjax())
    {
    //部分渲染(案例2)
    $view->disableLevel(数组)(
    视图::LEVEL_布局=>true,
    视图::LEVEL_MAIN_布局=>true
    ));
    }
    //默认为正常渲染
    其他的
    {
    //布局渲染(案例1)
    }
    }
    }
    }
    

    如何在应用程序范围内实现此机制,而不是在每个操作中重复此行为?

    最简单的方法是以统一的格式(如果还没有)将数据收集在一起,并将其传递给基本控制器中的方法,以与示例中所示的方式大致相同的方式处理该逻辑

    abstract class AbstractController extends \Phalcon\Mvc\Controller
    {
    
        protected function prepareResponse($data)
        {
    
            // JSON is identified
            if ($this->request->getBestAccept() == 'application/json')
            {
                // JSON rendering (case 3)
                $this->response->setContentType('application/json');
                $this->response->setJsonContent($data);
                $this->view->disable();
                return $this->response;
            }
    
            // Otherwise, defaults to HTML
    
            // Passing data to the view
            $this->view->setVars($data);
    
            // Ajax call is identified
            if ($this->request->isAjax())
            {
                // Partial rendering (case 2)
                $view->disableLevel(array(
                    View::LEVEL_LAYOUT => true,
                    View::LEVEL_MAIN_LAYOUT => true
                ));
            }
            // Defaults to normal rendering
            else
            {
                // Layout rendering (case 1)
            }
    
            return null;
        }
    }
    
    class ProductsController extends AbstractController
    {
    
        public function indexAction()
        {
            // Build data and prepare response
            return this->prepareResponse(array(
                'products' => Products::find(array(
                   'foo' => $this->request->get('foo')
                ))
            ));
        }
    }   
    
    否则,这可能有点棘手。我看到了以下备选方案

    例如,使用
    renderJson
    renderPartial
    方法扩展基本控制器,以处理这些逻辑位(默认情况下除外),但在您的操作中,仍然需要检查要调用哪一个。复制


    对路由器执行一些疯狂的操作,以执行不同的操作,例如,
    indexJsonAction
    indexPartialAction
    (默认情况下为其他),具体取决于条件。但你最终会遇到臃肿的控制器。

    我想没有内置的准备响应吧?(类似于)有,但不是那种,因为“最终准备响应”发生在
    handle
    方法中的调度程序和应用程序中。你可以覆盖它们,但我认为这不会有任何好处。还有一些可能是有用的,但它不是像上面那样高效/优雅的解决方案。它感觉你在寻找一种“真正的Phalcon方法”来做到这一点:)幸运的是,它并没有为每个问题提供解决方案,所以不要因为以你想要/需要的方式扩展它而感到内疚。我知道,以上是回答你问题的完美方法——比事件或其他任何事情都好。事实上,我是这样的,因为我一周前才发现:)我目前正试图“坚持书本”,而不是深入“重新发明轮子”。