Zend Framework 2 : Step by Step Create Custom View Strategy
Zend Framework 2 ships with three Rendering and Response Strategies that we can use within our application : PhpRendererStrategy, JsonStrategy, and FeedStrategy. If we want to use a custom strategy, for example : add content-type : image/png to all header response, we should create custom view strategy to create custom response. I will give you an example how to create it.
1. create a view strategy
namespace YourModule\View\Strategy;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;
use Zend\View\Renderer\RendererInterface;
use Zend\View\ViewEvent;
use Zend\View\Model\ViewModel;
class ImageStrategy implements ListenerAggregateInterface
{
protected $renderer;
protected $listeners = array();
public function __construct(RendererInterface $renderer)
{
$this->renderer = $renderer;
}
public function attach(EventManagerInterface $events, $priority = 1)
{
$this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, array($this, 'selectRenderer'), $priority);
$this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'injectResponse'), $priority);
}
public function selectRenderer(ViewEvent $e)
{
return $this->renderer;
}
public function injectResponse(ViewEvent $e)
{
$renderer = $e->getRenderer();
if ($renderer !== $this->renderer) {
return;
}
$result = $e->getResult();
$response = $e->getResponse();
$response->setContent($result);
$headers = $response->getHeaders();
$headers->addHeaderLine('content-type', 'image/png');
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
}
2. Create Factory
namespace YourModule\View\Strategy;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class ImageFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$viewRenderer = $serviceLocator->get('ViewRenderer');
return new ImageStrategy($viewRenderer);
}
}
3. Register in service manager
return array(
'factories' => array(
'ImageStrategy' => 'YourModule\View\Strategy\ImageFactory',
)
);
4. Register in view_manager in your module.config.php
'view_manager' => array(
'strategies' => array(
'ImageStrategy'
),
),
Done !
What if we need the custom strategy is for specific module ? This is it :
namespace YourModule;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sm = $e->getApplication()->getServiceManager();
$sharedEvents->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH, function($e) use ($sm) {
$strategy = $sm->get('ImageStrategy');
$view = $sm->get('ViewManager')->getView();
$strategy->attach($view->getEventManager());
}, 100);
}
public function getServiceConfig()
{
return array(
'factories' => array(
'ImageStrategy' => 'YourModule\View\Strategy\ImageFactory',
)
);
}
public function getAutoloaderConfig(){ /*common code */ }
public function getConfig(){ /*common code */ }
}
Testing, read image file from your controller :
namespace YourModule\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class SkeletonController extends AbstractActionController
{
public function fooAction()
{
return readfile('./public/images/zf2-logo.png');
}
}
Reference :
1. http://zf2.readthedocs.org/en/latest/modules/zend.view.quick-start.html
2. http://juriansluiman.nl/en/article/119/attach-a-view-strategy-for-specific-modules
[...] http://samsonasik.wordpress.com/2012/12/10/zend-framework-2-step-by-step-create-custom-view-strategy… [...]
Siiip…
offtopic: how can i get AuthenticationService in custom view helper because i get
__PHP_Incomplete_Class Object
setAuthService(new AuthenticationService);
if ($this->getAuthService()->hasIdentity()) {
$user = $this->getAuthService()->getIdentity();
print_r($user);
// $displayName = $user->getDisplayName();
// if (null === $displayName) {
// $displayName = $user->getUsername();
// }
// if (null === $displayName) {
// $displayName = $user->getEmail();
// $displayName = substr($displayName, 0, strpos($displayName, ‘@’));
// }
}
return $displayName;
}
public function getAuthService() {
return $this->authService;
}
public function setAuthService(AuthenticationService $authService) {
$this->authService = $authService;
return $this;
}
}
you should inject by service manager. create your view helper first.
namespace SanCommons\View\Helper; use Zend\View\Helper\AbstractHelper; class AuthServiceHelper extends AbstractHelper { protected $authservice; public function setAuthService($service) { $this->authservice = $service; } public function getAuthService() { return $this->authservice; } public function __invoke($display = null) { $user = $this->getAuthService()->getIdentity(); if (null === $displayName) { // return something.. } else { // return other something... } } }Register into Service Manager.
'view_helpers' => array( 'factories' => array( 'AuthServiceHelper' => function($sm){ $helper = new \SanCommons\View\Helper\AuthServiceHelper; //please make sure AuthService already registered in SM $request = $sm->getServiceLocator()->get('AuthService'); $helper->setAuthService($request); return $helper; } ), ),Calling in view :
echo $this->AuthServiceHelper('user');i use \DoctrineModule\Authentication\Adapter\ObjectRepository and i think the problem is when the object are serialize and saved to session, i extended that class and change object with array to solve the problem, but i will try your way to see if it’s working
Is there something like ZF1 AjaxContext which verify ‘X-Requested-With: XmlHttpRequest’ header?
read my prev article : http://samsonasik.wordpress.com/2012/12/02/zend-framework-2-disable-layout-in-specific-module/
Thanks, now i’ll swich viewmodel to jsonViewModel
You’re welcome
Hello, I am struggling with setting xsl stylesheets to use for views. Do you have any resource where this would be explained? I tried using this blog and define a new strategy but it seems there’s much more to it. Thanks.
Additionaly, when trying to reproduce you png view strategy. I get following exception:
While attempting to create imagestrategy(alias: ImageStrategy) an invalid factory was registered for this instance type.
thrown at line where you assign $strategy in onBootsrap in Module:
$strategy = $sm->get(‘ImageStrategy’);
I could not resolve this problem. Thanks for any advice
add the following functions to your Module.php
public function getConfig() { return include __DIR__ . '/config/module.config.php'; } public function getAutoloaderConfig() { return array( 'Zend\Loader\StandardAutoloader' => array( 'namespaces' => array( __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, ), ), ); }one more thing, don’t forget to look at the name of file and name of namespace, adapt to your created module.
Thank you very much. I already had these 2 methods set up the same way as you suggested, but the problem was elsewhere, I have created the View subdir under src/ and not under src/Application so I had:
src/
Application/
Controller/
View/
I needed to move it to get
src/
Application/
Controller/
View/
The settings is obvious from namespace but I missed that and spent lot of time on this. Anyway, very good blog thanks and keep up.
white space removed, so I’m gonna try again:
wrong dir structure (if you want the code from this blog to work):
src/
–Application/
—-Controller/
–View/
correct:
src/
–Application/
—-Controller/
—-View/
module --Application --src --Application --View --Strategy --ImageStrategy.php --ImageFactory.php --Controller --SkeletonController.php --config --module.config.php Module.php