Message-ID: <1102418857.3228.1485852451515.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_3227_1133433217.1485852451514" ------=_Part_3227_1133433217.1485852451514 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
In some cases, displaying a Content item/Location via the built-in ViewController
is not sufficient and will force you to make many su=
b-requests in order to access different parameters.
Typical use cases are access to:
ConfigResolver
or Servi=
ceContainer
)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:
ezpublish: system: my_siteaccess: location_view: full: # Defining a ruleset matching a location and pointing t= o a controller my_ruleset: # The following will let you use your own custom co= ntroller for location #123 # (Here it will use AcmeTestBundle/Controller/Defau= ltController::viewLocationAction(), # following the Symfony controller notation convent= ion. # Method viewLocationAction() must follow the same = prototype as in the built-in ViewController controller: AcmeTestBundle:Default:viewLocation match: Id\Location: 123=20
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 signa=
ture 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 cl=
ever enough to know what to inject into your action method . That is wh=
y you aren't forced to mimic the ViewController
's sign=
ature strictly. For example, if you omit $layout
and =
$params
arguments, it will still be valid. Symfony will just a=
void 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 =3D false, ar= ray $params =3D array() )=20
/** * 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 =3D false, arra= y $params =3D array() )=20
Note
Controller selection doesn't apply to block_view
since you =
can already use your own controller to display bloc=
ks.
Warning on caching
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&=
nbsp; X-Location-Id
header in the return=
ed Response
object.
See built-in ViewController fo= r more details on this.
This example shows how to use a custom controller to enrich the final co=
nfigured view template. Your controller will here forward the request to th=
e built-in ViewController
with some additional param=
eters.
Always ensure that you add new parameters to existing $params associative array, using
+
union operator or array_merge() .
Not doing so (e.g. only passing your custom parameters a=
rray) can result in unexpected issues with content preview. Previe=
wed content and other parameters are indeed passed in $params
.=
ezpublish: system: ezdemo_frontend_group: location_view: full: article_test: # Configuring both controller and template as the c= ontroller will forward # the request to the ViewController which will rend= er the configured template. controller: AcmeTestBundle:Default:articleViewEnhan= ced template: AcmeTestBundle:full:article_test.html.twi= g match: Identifier\ContentType: [article]=20
<?php namespace Acme\TestBundle\Controller; use Symfony\Component\HttpFoundation\Response; use eZ\Bundle\EzPublishCoreBundle\Controller; class DefaultController extends Controller { public function articleViewEnhancedAction( $locationId, $viewType, $lay= out =3D false, array $params =3D array() ) { // Add custom parameters to existing ones. $params +=3D array( 'myCustomVariable' =3D> "Hey, I'm a custom m= essage!" ); // Forward the request to the original ViewController // And get the response. Eventually alter it (here we change the sm= ax-age for cache). $response =3D $this->get( 'ez_content' )->viewLocation( $loca= tionId, $viewType, $layout, $params ); $response->setSharedMaxAge( 600 ); return $response; } }=20
{% extends noLayout ? viewbaseLayout : "eZDemoBundle::pagelayout.ht= ml.twig" %} {% block content %} <h1>{{ ez_render_field( content, 'title' ) }}</h1> <h2>{{ myCustomVariable }}</h2> {{ ez_render_field( content, 'body' ) }} {% endblock %}=20
This example shows you how to configure and use your own controller to h= andle a location.
ezpublish: system: ezdemo_frontend_group: location_view: full: my_ruleset: controller: AcmeTestBundle:Default:viewFolder match: Identifier\ContentType: [folder] Identifier\Section: [standard]=20
Always ensure to have a $params
argument and add new parame=
ters to it, using +
union operator or array_merge()
.
Not doing so (e.g. only passing your custom parameters array) ca=
n result in unexpected issues with content preview. Previewed cont=
ent and other parameters are indeed passed in $params
.
<?php namespace Acme\TestBundle\Controller; use Symfony\Component\HttpFoundation\Response; use eZ\Bundle\EzPublishCoreBundle\Controller; class DefaultController extends Controller { public function viewFolderAction( $locationId, $layout =3D false, $para= ms =3D array() ) { $repository =3D $this->getRepository(); $location =3D $repository->getLocationService()->loadLocation= ( $locationId ); // Check if content is not already passed. Can be the case when usi= ng content preview. $content =3D isset( $params['content'] ) ? $params['content'] : $re= pository->getContentService()->loadContentByContentInfo( $location-&g= t;getContentInfo() ) $response =3D 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' =3D> $location, 'content' =3D> $content, 'foo' =3D> 'Hey world!!!', 'osTypes' =3D> array( 'osx', 'linux', 'losedows' ) ) + $params ); } }=20
{% 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 %}=20
One other way to keep control of what is passed to the view is to use yo= ur own controller instead of the built-in ViewController.
Base ViewController being defined as a service, with a service alias, th= is 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=20
Warning
Doing so will completely override the built-in ViewController! Use this = at your own risk!
See also