ZF2 set custom URL/route and view - zend-framework2

I am using ZF2 as a component of another application.
I am looking for a way to set the URL and View Template of the application between an init() and a run() call. I would like a way to either modify the Request and Response objects, or regenerate them with a different URL.
I currently use ob_start() and ob_get_clean() and a view template that simply generates the_content, thus injecting the output of ZF2 inside a page of another application.
Any suggestions on methodology would be appreciated.

In Module.php you can attach event to event manager for exemple.
class Module
{
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
$serviceManager = $e->getApplication()->getServiceManager();
$eventManager->attach(MvcEvent::EVENT_ROUTE, function($e) use ($eventManager, $serviceManager){
// your code here
}, -1000);
}
}
Or your action in your controller can dispatch another action and get the result
in action method :
$return = $this->forward()->dispatch('controllerName', array('action' => 'actionName', 'param1' => 'value', ...));

The following code inside another application can be used to set the calling URL and View Template from outside of the application:
$bootstrap = \Zend\Mvc\Application::init( include( '/zf2/config/application.config.php' ) );
$event = $bootstrap->getMvcEvent( );
/* Modify the event with a custom request. */
$request = new \Zend\Http\Request( );
$request->setMethod( \Zend\Http\Request::METHOD_GET );
$request->setUri( $custom_url );
$event->setRequest( $request );
/* Modify the view. */
$event->getViewModel()->setTemplate('layout/custom-layout');
ob_start( );
$bootstrap->run( );
$html = ob_get_clean( );

Related

ZF2 Nesting Views in View Helper

I'm attempting to create a ZF2 view helper which outputs a blog post of varying display formats.
The post is made up of a header, body and footer.
I've attempted to create the view helper using the nesting example in the ZF2 docs.
// post helper
public function __invoke( PostInterface $post, $is_single = true ){
$view_model = new ViewModel();
$view_model->setTemplate( 'editorial/partials/complete' );
$view_model->setVariable( 'object', $post );
$view_model->setVariable( 'is_single', $is_single );
$body_model = new ViewModel();
$body_model->setTemplate( 'editorial/partials/xx_display_format_partial_xx' );
$body_model->setVariable( 'object', $post );
$view_model->addChild( $body_model, 'body' );
... repeat for header and footer
return $this->getView()->render( $view_model );
}
// editorial/partials/complete.phtml
echo $this->header;
echo $this->body;
echo $this->footer;
I receive no errors when echoing the view helper. The problem is, there's no output either.
Is what I'm trying to do even possible? If so, what am I doing wrong?
Try this solution https://stackoverflow.com/a/15193978/981820
It says that that PphRenderer actually does not render the child views. The tutorial shows how it works from the action point of view, and it works because in that case the view is rendered by Zend\View\View::render()
So, the solution to your problem is to render your nested views the same way it's done there.
UPDATED
Or you can do it even simpler. Just render your views separately and attach each output to your main view as a variable. See an example:
$view = new ViewModel();
$body = new ViewModel();
$header = new ViewModel();
$footer = new ViewModel();
//... some setup
$view->setVariable('body', $this->getView()->render($body));
$view->setVariable('header', $this->getView()->render($header));
$view->setVariable('footer', $this->getView()->render($footer));
return $this->getView()->render($view);
It should be the same outcome and more optimized in terms of your task. The reason why the code from the Zend\View\View::render() is more complex than this one it's because it oversees all the possible cases, but you don't have to do the same for your task.
try this :
create the child model first and then set the child model as a variable for the parent model
$body_model = new ViewModel();
$body_model->setTemplate( 'editorial/partials/xx_display_format_partial_xx' );
$body_model->setVariable( 'object', $post );
$view_model = new ViewModel();
$view_model->setTemplate( 'editorial/partials/complete' );
$view_model->setVariable( 'object', $post );
$view_model->setVariable( 'is_single', $is_single );
$view_model->setVariable( 'body', $body_model );//<-----------------------------

How to use form view helper into custom view helper in zend framework 2

I am creating custom view helper. and i want to know how can i use formElement "Zend\Form\View\Helper\FormElement" in my own view helper. Here is my code.
use Zend\Form\ElementInterface;
use Zend\Form\FieldsetInterface;
use Zend\Form\View\Helper\FormElement;
use Zend\Form\View\Helper\AbstractHelper;
use Zend\View\Renderer\PhpRenderer;
class JudgeCareerViewHelper extends AbstractHelper {
private $output;
public function __invoke($formCollection) {
foreach ($formCollection as $elementOrFieldset) {
if ($elementOrFieldset instanceof FieldsetInterface) {
$obj = new FormElement();
$this->output .= $obj($elementOrFieldset->get('startServiceDate'));
} elseif ($elementOrFieldset instanceof ElementInterface) {
//set element markup
echo 'element';
}
};
echo $this->output;
die();
}
}
When i echo the output return from FormElement is empty. So i opened the zend "Zend\Form\View\Helper\FormElement" library to find out where is the problem. So i found that, below code return empty. I dont know what is the purpose of $renderer = $this->getView(); and how to get view.
$renderer = $this->getView();
if (!method_exists($renderer, 'plugin')) {
// Bail early if renderer is not pluggable
return '';
}
Purpose of creating custom view helper to generate my own markup (HTML) instead of zend buitin html.
So I found that, code $renderer = $this->getView() return empty.
You will need to ensure that the view helper is not directly instantiated using new but is called via the Zend\View\HelperPluginManager.
I suspect that the issue is because it is not correctly registered with the service manager as an invokable class.
// Module.php
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'JudgeCareer'
=> 'FooModule\Form\View\Helper\JudgeCareerViewHelper',
),
);
}
This is to ensure that the Zend\View\Renderer\PhpRenderer is injected as the view.
Once the JudgeCareerViewHelper has the 'view' injected it would then be able to call other view plugins and have them loaded correctly, again via the HelperPluginManager.
The line:
$obj = new FormElement();
Should then be
$object = $this->getView()->plugin('form_element');
You may call any view helper from within your custom view helper by using
$this->getView()->anyRegisteredViewHelper();
So in your case to call the ZF2 built in form rendering view helpers you would use:
$this->getView()->formElement($element);
Whereby $element is your Form Element object (Select/Textarea/Checkbox etc)
You can of course also call explicit helpers for specific elements:
$this->getView()->formTextarea($textareaElement);

How to end the execution of an action via an event

in my ZF2 application I am adding the following event listener, however I want to make the execution of the action actually stop, however this doesnt happen.
public function setEventManager(EventManagerInterface $events)
{
parent::setEventManager($events);
$controller = $this;
$events->attach('dispatch', function ($e) use ($controller) {
$request = $e->getRequest();
$method = $request->getMethod();
$headers = $request->getHeaders();
// If we get here, based on some conditions, the original intended action must return a new JsonViewModel()...
return new JsonViewModel([]); // However, this doesn't do anything.
}, 100); // execute before executing action logic
}
Based on your comments, I am assuming you are doing some sort of authentication. You can perfecty use the event manager for this. However, I would not tie the listener to a single controller. If your API increases, you might want to split the API over several controllers and you get into trouble with your authentication.
My solution is to create a listener which listens to the dispatch event of the Zend\Mvc\Application. This is an event which is triggered before the event in the controllers itself.
use Zend\Mvc\MvcEvent;
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$em = $app->getEventManager();
$sm = $app->getServiceManager()->getSharedManager();
$listener = new Listener\Authentication();
$identifier = 'MyModule\Controller\ApiController';
$em->attach($identifier, MvcEvent::EVENT_DISPATCH, $listener, 1000);
}
This way, the listener is attached to all controllers which are identified with MyModule\Controller\ApiController. The listener will be triggered on every dispatch call of those controllers. Your listener can short-circuit the complete dispatch loop in case you need it:
use Zend\Http\Request as HttpRequest;
use Zend\Mvc\MvcEvent;
use Zend\Json\Json;
use Zend\View\Model\JsonModel;
class Authentication
{
public function __invoke(MvcEvent $e)
{
$request = $e->getRequest();
if (!$request instanceof HttpRequest) {
// Don't run on CLI requests
return;
}
if ($result->isValid()) {
// Say you get auth result and all is OK
return;
}
// Case 1: short-circuit and return response, this is the fast way
// The response I use here is the HTTP problem API
$message = array(
'httpStatus' => 401,
'title' => 'Unauthorized',
'detail' => 'You are unauthorized to perform this request',
);
$response = $e->getResponse();
$response->setStatusCode(401);
$response->getHeaders()->addHeaderLine('Content-Type', 'application/json');
$response->setContent(Json::encode($message);
return $response;
// Case 2: don't short circuit and stop propagation, you're using the JSON renderer
$e->getResponse()->setStatusCode(401);
$message = array(
'httpStatus' => 401,
'title' => 'Unauthorized',
'detail' => 'You are unauthorized to perform this request',
);
$model = new JsonModel($message);
return $model;
}
}
I would advice you to use the first method (returning the response yourself) because you'll short circuit the complete dispatch process and skip the complete finishing of the request. If you really rely on the view and response senders, use the second case.
Now if you need a controller which is authenticated via this system, add the identifier to this controller:
namespace MyModule\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class MyFooBarApiController extends AbstractActionController
{
protected $eventIdentifer = 'MyModule\Controller\ApiController';
// your code here
}
If you need to allow certain requests without validation (I would always use a whitelist!), you can do this in your listener:
use Zend\Mvc\Route\RouteMatch;
$routematch = $e->getRouteMatch();
if (!$routematch instance of RouteMatch) {
// It's a 404, don't perform auth
return;
}
$route = $routematch->getMatchedRouteName();
if (
($request->isPost() && 'foo/bar' === $route)
|| ($request->isGet() && 'baz/bat' === $route)
) {
// We allow these requests to pass on without auth
return;
}
In your code you can explicitly check request method and route name. If you need parameters of the route, you can access it with $routematch->getParam('id').
Use the following in your event:
$e->stopPropagation();

Set layout variables for use by the (404) error pages in ZF2

At present I set a couple of variables to be used by the app's overall layout.phtml, using the onDispatch method of a BaseController, which all my other controllers extend:
public function onDispatch(MvcEvent $e)
{
$config = $this->getServiceLocator()->get('config');
$this->layout()->setVariable('platformName', $config['platform']['name']);
$this->layout()->setVariable('platformYear', $config['platform']['year']);
}
This works fine, until I test some error pages and find that these pages do not get provided with the variables, as it's not using the base controller.
How can I get around this problem and provide the error pages with the same variables?
Change the event you're listening for.
In this case, I'd move this logic to the application bootstrap event or the application render event (I haven't tested this, but it would probably work fine).
One example, in your Module.php
public function onBootstrap($e)
{
$config = $e->getApplication()->getServiceManager()->get('config');
//$e->getViewModel()->setVariable();
}
Haven't tested that commented out line, but it should get you headed in the right direction.
EDIT: Found an example of using the render event
public function onBootstrap($e)
{
$event = $e->getApplication()->getEventManager();
$event->attach('render', function($e) {
$config = $e->getApplication()->getServiceManager()->get('config');
$e->getViewModel()->setVariable('test', 'test');
});
}
(Necro)
When using onDispatch in a Controller, remember to return the parent with the event and all:
public function onDispatch(MvcEvent $e)
{
// Your code
return parent::onDispatch($e);
}
Otherwise, the logic on your Actions in that Controller will be ignored.

How to get URL params in ViewHelper with Zend Framework 2

I've created simple ViewHelper with http://blog.evan.pro/creating-a-simple-view-helper-in-zend-framework-2. How to get URL params in this helper? $this->params('param') works only in controllers...
Given the code from the blog post, you can use this code from inside the view helper:
$this->request->getPost('param'); // post parameter
// or
$this->request->getQuery('param'); // query parameter
The code from the example receives an instance of the Zend\Http\Request object for the current request and stores it in the property called request of the view helper so you can use the request property to access the Request object and information from it.
In view helper you have to add code like this:
Module.php
'factories' => array(
'myViewHelper' => function($pm) {
return new MyView($pm);
},
)
Now in Helper Class file your have to add following piece of code
public function __construct($pm) {
$this->pluginManager = $pm;
$this->serviceLocator = $this->pluginManager->getServiceLocator();
$this->routeMatch = $this->serviceLocator->get('Router')->match($this->serviceLocator->get('Request'));
}
public function __invoke() {
$params = $this->getRouteMatch()->getParams();
}
Here $params will return all route params in array formate.

Resources