4

I'm developing a RESTful application and I want to build a factory that creates the proper ViewModel (Zend\View\Model\ViewModel, Zend\View\Model\JsonModel, my XmlModel) object dependent on the Accept (e.g. -H 'Accept: application/json') parameter in the HTTP request header. I want to implement this as a callback:

class Module implements ServiceProviderInterface
{

...

    public function getServiceConfig() {
        try {
            return array (
                'factories' => array(
                    'RestViewModel' => function($serviceManager) {
                        // Here I need the the Request object.
                        $requestHeadAccept = $requestObject->getHeaders()->get('Accept')->toString();
                        $return = null;
                        if (strpos($requestHeadAccept, 'application/json') != -1) {
                            $return = new JsonModel(array('data' => $data));
                        } elseif (strpos($requestHeadAccept, 'application/xml') != -1) {
                            ...
                        } else {
                            ...
                        }
                        return $return;
                    }
                )
            );
        } catch (\Exception $e) {
            ...
        }
    }

...

}

How can I get the Request object at this place?

smottt
  • 3,272
  • 11
  • 37
  • 44
automatix
  • 14,018
  • 26
  • 105
  • 230

2 Answers2

16

The short answer: the request is registered as Request:

$request = $serviceManager->get('Request');

However, what you aims to achieve is not a piece that belongs to the service manager's factories. It is a context dependant factory required in the controller domain. Therefore, I would create is as a controller plugin.

And to be honest, this feature is already available in ZF2 via an existing controller plugin called acceptableViewModelSelector. An example is available at the manual but this would be the scenario in your case:

use Zend\Mvc\Controller\AbstractActionController;

class SomeController extends AbstractActionController
{
   protected $acceptCriteria = array(
      'Zend\View\Model\JsonModel' => array(
         'application/json',
      ),
      'My\View\XmlModel' => array(
         'application/xml',
      ),
   );

   public function apiAction()
   {
      $model = $this->acceptableViewModelSelector($this->acceptCriteria);
   }
}

Then you will get either a JsonModel, XmlModel or by default the ViewModel.

Jurian Sluiman
  • 13,498
  • 3
  • 67
  • 99
  • Great! Thank you very much for your answer! One more question: what's about not expected `Accept` values? I've just tried `application/foobar` out and got a `Zend\View\Model\ViewModel` object and a `Zend\View\Exception\RuntimeException` (thrown in `/vendor/ZF2/library/Zend/View/Renderer/PhpRenderer.php:499`). How should cases be handled, when the HTTP request header contains a not proper `Access` value? – automatix Jun 18 '13 at 14:10
  • @automatix I think this is a different question, but here it goes: 1) you get a ViewModel by default when no proper match can be found. This is what you want, right? And 2) What is the exception and why is it thrown? Can you clarify? – Jurian Sluiman Jun 19 '13 at 07:16
  • @automatix I see the exception now, it's about the template that cannot be found. If you return a `ViewModel` then a rendering with a phtml file is made to return html in the response. Thus, returning a view model means you need a template to be rendered. You can alter the behaviour not to return a standard ViewModel, but for example standard you return a JSON model. Is that what you need? – Jurian Sluiman Jun 19 '13 at 07:23
2

Creating and Registering Alternate Rendering and Response Strategies

http://framework.zend.com/manual/2.0/en/modules/zend.view.quick-start.html#creating-and-registering-alternate-rendering-and-response-strategies

Haver
  • 443
  • 2
  • 11
  • Thank you! Yes, that also seems to be a good solution. But the same question as above: How to handle cases, when the HTTP request header contains a not proper Access value? – automatix Jun 18 '13 at 15:15
  • 1
    Not sure if I am understanding you question properly, but I will give it a try. In you module.config.php add key 'strategies' => array('ViewJsonStrategy'). then your module now knows not to use a view script for any JsonModels returned. check the blog http://spabby.github.io/zend-framework-2-REST/ – Haver Jun 18 '13 at 15:47