Navigation
eZ Documentation Center
 

This is outdated documentation made for eZ Publish Platform 5.2. It is being moved into the eZ Publish 5.x documentation, so please go there for most up-to-date documentation.

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
Note
titleVersion compatibility

This recipe is compatible with eZ Publish 5.2 / 2013.07

Table of Contents

Enhanced views for Content/Location

In some cases, displaying a content/location via the built-in ViewController is not sufficient and will lead you to do many sub-requests in order to access different parameters.

Typical use cases are access to:

  • Settings (either coming from ConfigResolver or ServiceContainer)
  • Current content's ContentType object
  • Current location's parent
  • Current location's children count
  • Main location and alternative locations for the current content
  • etc…

In those cases, you may want to use your own controller to display the current content/location instead of using the built-in ViewController.

Description

This feature covers 2 general use cases:

  • Lets you configure a custom controller with the configured matcher rules.
  • Lets you override the built-in view controller in a clean way.

Matching custom controllers

This is possible with the following piece of configuration:

Code Block
ezpublish:
    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
Info

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 in your action method. Hence you're not forced to mimic the ViewController's signature strictly. For example, if you omit $layout and $params arguments, it will be still valid. Symfony will just avoid to inject them in your action method.

Original ViewController signatures

Code Block
languagephp
titleviewLocation() signature
/**
 * 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() )
Code Block
languagephp
titleviewContent() signature
/**
 * 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() )
Info
titleNote

Controller selection doesn't apply to block_view since you can already use your own controller to display blocks.

Warning
titleWarning 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 X-Location-Id header in the returned Response object.

See built-in ViewController for more details on this.

Examples

Using a custom controller to get full control

This example shows you how to configure and use your own controller to handle a location.

Code Block
titleezpublish.yml
ezpublish:
    system:
        ezdemo_frontend_group:
            location_view:
                full:
                    my_ruleset:
                        controller: AcmeTestBundle:Default:viewFolder
                        match:
                            Identifier\ContentType: [folder]
                            Identifier\Section: [standard]
Code Block
languagephp
titleController
<?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 )
    {
        $repository = $this->getRepository();
        $location = $repository->getLocationService()->loadLocation( $locationId );
        $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' => $repository->getContentService()->loadContentByContentInfo( $location->getContentInfo() ),
                'foo' => 'Hey world!!!',
                'osTypes' => array( 'osx', 'linux', 'losedows' )
            )
        );
    }
}

Code Block
titlecustom_controller_folder.html.twig
{% 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 %}

Enriching the built-in ViewController

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.

Code Block
titleezpublish.yml
ezpublish:
    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]
Code Block
languagephp
titleController
<?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() )
    {
        $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;
    }
}
Code Block
titlearticle_test.html.twig
{% 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 %}

 

Overriding the built-in ViewController

One other way to keep control on 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:

Code Block
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
Warning
titleWarning

Doing so will completely override the built-in ViewController! Use this at your own risk!

Info
titleSee also

See also How to Display a default text while asynchronous loading of a controller