
In some cases, displaying a Content item/Location via the built-in ViewController is not sufficient and will force you to make many sub-requests in order to access different parameters.
Typical use cases are access to:
ConfigResolver or ServiceContainer)ContentType objectIn those cases, you may want to use your own controller to display the current Content item/Location instead of using the built-in ViewController.
This feature covers 2 general use cases:
This is possible with the following piece of configuration:
exponential:
system:
my_siteaccess:
location_view:
full:
# Defining a ruleset matching a location and pointing to a controller
my_ruleset:
# The following will let you use your own custom controller for location #123
# (Here it will use AcmeTestBundle/Controller/DefaultController::viewLocationAction(),
# following the Symfony controller notation convention.
# Method viewLocationAction() must follow the same prototype as in the built-in ViewController
controller: AcmeTestBundle:Default:viewLocation
match:
Id\Location: 123 |
You can point to any kind of controller supported by Symfony (including controllers as a service). |
The only requirement here is that your action method has a similar signature than ViewController::viewLocation() or ViewController::viewContent() (depending on what you're matching of course). However, note that all arguments are not mandatory since Symfony is clever enough to know what to inject into your action method . That is why you aren't forced to mimic the ViewController's signature strictly. For example, if you omit $layout and $params arguments, it will still be valid. Symfony will just avoid injecting them into your action method.
/** * Main action for viewing content through a location in the repository. * * @param int $locationId * @param string $viewType * @param boolean $layout * @param array $params * * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException * @throws \Exception * * @return \Symfony\Component\HttpFoundation\Response */ public function viewLocation( $locationId, $viewType, $layout = false, array $params = array() ) |
/** * Main action for viewing content. * * @param int $contentId * @param string $viewType * @param boolean $layout * @param array $params * * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException * @throws \Exception * * @return \Symfony\Component\HttpFoundation\Response */ public function viewContent( $contentId, $viewType, $layout = false, array $params = array() ) |
Controller selection doesn't apply to |
Using your own controller, it is your responsibility to define cache rules, like for every custom controller ! So don't forget to set cache rules and the appropriate See built-in ViewController for more details on this. |
This example shows how to use a custom controller to enrich the final configured view template. Your controller will here forward the request to the built-in ViewController with some additional parameters.
| This is usually the recommended way to use a custom controller. |
Always ensure that you add new parameters to existing |
exponential:
system:
ezdemo_frontend_group:
location_view:
full:
article_test:
# Configuring both controller and template as the controller will forward
# the request to the ViewController which will render the configured template.
controller: AcmeTestBundle:Default:articleViewEnhanced
template: AcmeTestBundle:full:article_test.html.twig
match:
Identifier\ContentType: [article] |
<?php
namespace Acme\TestBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use eZ\Bundle\EzPublishCoreBundle\Controller;
class DefaultController extends Controller
{
public function articleViewEnhancedAction( $locationId, $viewType, $layout = false, array $params = array() )
{
// Add custom parameters to existing ones.
$params += array( 'myCustomVariable' => "Hey, I'm a custom message!" );
// Forward the request to the original ViewController
// And get the response. Eventually alter it (here we change the smax-age for cache).
$response = $this->get( 'ez_content' )->viewLocation( $locationId, $viewType, $layout, $params );
$response->setSharedMaxAge( 600 );
return $response;
}
} |
{% extends noLayout ? viewbaseLayout : "eZDemoBundle::pagelayout.html.twig" %}
{% block content %}
<h1>{{ ez_render_field( content, 'title' ) }}</h1>
<h2>{{ myCustomVariable }}</h2>
{{ ez_render_field( content, 'body' ) }}
{% endblock %} |
This example shows you how to configure and use your own controller to handle a location.
exponential:
system:
ezdemo_frontend_group:
location_view:
full:
my_ruleset:
controller: AcmeTestBundle:Default:viewFolder
match:
Identifier\ContentType: [folder]
Identifier\Section: [standard] |
Always ensure to have a Not doing so (e.g. only passing your custom parameters array) can result in unexpected issues with content preview. Previewed content and other parameters are indeed passed in |
<?php
namespace Acme\TestBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use eZ\Bundle\EzPublishCoreBundle\Controller;
class DefaultController extends Controller
{
public function viewFolderAction( $locationId, $layout = false, $params = array() )
{
$repository = $this->getRepository();
$location = $repository->getLocationService()->loadLocation( $locationId );
// Check if content is not already passed. Can be the case when using content preview.
$content = isset( $params['content'] ) ? $params['content'] : $repository->getContentService()->loadContentByContentInfo( $location->getContentInfo() )
$response = new Response();
$response->headers->set( 'X-Location-Id', $locationId );
// Caching for 1h and make the cache vary on user hash
$response->setSharedMaxAge( 3600 );
$response->setVary( 'X-User-Hash' );
return $this->render(
'AcmeTestBundle::custom_controller_folder.html.twig',
array(
'location' => $location,
'content' => $content,
'foo' => 'Hey world!!!',
'osTypes' => array( 'osx', 'linux', 'losedows' )
) + $params
);
}
}
|
{% extends "eZDemoBundle::pagelayout.html.twig" %}
{% block content %}
<h1>{{ ez_render_field( content, 'title' ) }}</h1>
<h1>{{ foo }}</h1>
<ul>
{% for os in osTypes %}
<li>{{ os }}</li>
{% endfor %}
</ul>
{% endblock %}
|
One other way to keep control of what is passed to the view is to use your own controller instead of the built-in ViewController.
Base ViewController being defined as a service, with a service alias, this can be easily achieved from your bundle's configuration:
parameters:
my.custom.view_controller.class: Acme\TestBundle\MyViewController
services:
my.custom.view_controller:
class: %my.custom.view_controller.class%
arguments: [@some_dependency, @other_dependency]
# Change the alias here and make it point to your own controller
ez_content:
alias: my.custom.view_controller |
Doing so will completely override the built-in ViewController! Use this at your own risk! |
See also How to Display a default text while asynchronous loading of a controller |