Message-ID: <670827204.2742.1485850606311.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_2741_1338822572.1485850606311" ------=_Part_2741_1338822572.1485850606311 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html Content Rendering

Content Rendering

=20
=20
=20
=20

Introduction

The ViewController

eZ Platform comes with a native controller to = display your content, known as the ViewController . It is called each time you try to reach a Content item from its Url Alias (human readable, translatable URI generat= ed for any content based on URL patterns defined per Content Type) and is a= ble to render any content previously edited in the admin interface or via t= he Public API Guide.

It can also be called straight by its direct URI: 

/view/content/<contentId>/full/true/<locationId>

/view/content/<contentId>

A Content item can also have different view types (full= page, abstract in a list, block in a landing page, etc.). By default the v= iew type is full (for full page), but it can be anything (= line, block, etc.).

Important note regarding visibility

The Location visibility flag, which you can change by hiding/revealing i= n the Platform UI, is not permission-based and thus acts as a simple potent= ial filter. It is not meant to restrict access to content.=

If you need to restrict access to a given Content item, use Sect= ions or Object states, which are permission-based= .

Configuration

View provider configu= ration

The configured ViewProvider allows you to configure tem= plate selection when using the ViewController, either directly= from a URL or via a sub-request.

eZ Publish 4.x terminology

In eZ Publish 4.x, it was known as template override system = by configuration (override.ini).
However thi= s only reflects old overrides for node/view/*.tpl and co= ntent/view/*.tpl.

Principle

The configured ViewProvider takes its configuration fro= m your siteaccess in the  content_view = section. This configuration is a hash built in the following = way:

app/config/ezplatform.yml
=20
ezpublish:
    system:
        # Can be a valid siteaccess, siteaccess group or even "global"
        front_siteaccess:
            # Configuring the LocationViewProvider
            content_view:
                # The view type (full/line are standard, but you can use cu=
stom ones)
                full:
                    # A simple unique key for your matching ruleset
                    folderRuleset:
                        # The template identifier to load, following the Sy=
mfony bundle notation for templates
                        # See http://symfony.com/doc/current/book/controlle=
r.html#rendering-templates
                        template: eZDemoBundle:full:small_folder.html.twig
                        # Hash of matchers to use, with their corresponding=
 values to match against
                        match:
                            # Key is the matcher "identifier" (class name o=
r service identifier)
                            # Value will be passed to the matcher's setMatc=
hingConfig() method.
                            Identifier\ContentType: [small_folder, folder]<=
/pre>=20

Important note about template matching

Template matching will NOT work if your content contains a Field= Type that is not supported by the repository. It can be the case = when you are in the process of a migration from eZ Publish 4.x, where custo= m datatypes have been developed.

In this case the repository will throw an exception, which is caught in = the ViewController, and if you are using Legacy= Bridge it will end up doing a fallback to legacy kern= el.

The list of Field Types supported out of the box is available here.

Tip

You can define your template selection rules in a different configuratio= n file. Read the cookbook recipe to learn more about = it .

You can also = use your own custom controller to render a content/location.

About = location_view & content_view

Until eZ Publish Platform 5.4, the main view action was location_v= iew. This is deprecated since eZ Platform 15.12 (1.0). Only content_view should be used to view content, with a location as a= n option.

Existing location_view rules will be, when possible, converted transparently to content_view, with a deprecation= notice. However, it is not possible to do so when the rule uses a custom c= ontroller.
In any case, location_view rules should be conve= rted to content_view ones, as location_view will = be removed in the next kernel major version.

Matchers

To be able to select the right templates against conditions, the view pr= ovider uses matcher objects, all implementing eZ\Publish\Core\MV= C\Symfony\View\ContentViewProvider\Configured\Matcher interface.

Matcher identifier

The matcher identifier can comply to 3 different formats:

  1. Relative qualified class name (e.g. Identifier\C= ontentType). This is the most common case and used for native matche= rs. It will then be relative to eZ\Publish\Core\MVC= \Symfony\Matcher\ContentBased.
  2. Full qualified class name (e.g. \Foo\Bar\MyMatch= er). This is a way to specify a custom matcher that= doesn't need specific dependency injection. Please note that it mu= st start with a \.
  3. Service identifier, as defined in Symfony service cont= ainer. This is the way to specify a more complex custom matcher that has dependencies.

Injecting the Repository

If your matcher needs the repository, simply make it implement eZ\= Publish\Core\MVC\RepositoryAwareInterface or extend the eZ\Pub= lish\Core\MVC\RepositoryAware abstract class. The repository will th= en be correctly injected before matching.

Matcher value

The value associated to the matcher is being passed to its se= tMatchingConfig() method and can be anything supported by the m= atcher.

In the case of native matchers, they support both=20 scalar values or=20 arrays of scalar values.=20
Passing an array amounts to applying a logical OR.

Combining matchers

It is possible to combine matchers to add additional constraints for mat= ching a template:

=20
# ...
match:
    Identifier\ContentType: [small_folder, folder]
    Identifier\ParentContentType: frontpage
=20

The example above can be translated as "Match any content which = ContentType identifier is small_folder OR fo= lder , AND having frontpage as ParentContentType identifier".

Available matchers

The following table presents all native matchers.

Identifier Description
Id\Content Matches the ID number of the Conte= nt item
Id\ContentType Matches the ID number of the Conte= nt Type that the Content item is an instance of
Id\ContentTypeGroup Matches the ID number of the= group containing the Content Type that the Content item is an instance of<= br>
Id\Location Matches the ID number of a Location.
In = the case of a Content item, matched against the main location.
Id\ParentContentType<= /td> Matches the ID number of the paren= t Content Type.
In the case of a Content item, matched against the = main location.
Id\ParentLocation

Matches the ID number of the pa= rent Location.
In the case of a Content item, matched against the m= ain location.

Id\Remote Matches the remoteId of either content or Locati= on, depending on the object matched.
Id\Section Matches the ID number of the Secti= on that the Content item belongs to.
Id\State Not supported yet.
Identifier\ContentType Matches the identifier of th= e Content Type that the Content item is an instance of.
Identifier\ParentContentType=

Matches the identifier of= the parent Content Type.
In the case of a Content item, matched ag= ainst the main Location. 

Identifier\Section Matches the identifier of the Sect= ion that the Content item belongs to.
Identifier\State Not supported yet.
Depth Matches the depth of the Loc= ation. The depth of a top level Location is 1.
UrlAlias

Matches the virtual URL o= f the Location (i.e. /My/Content-Uri).

Important: Matches when the UrlAlias of the location starts with the value passed.
Not supported for Content (aka c= ontent_view). 

Default view templates

Content view uses default templat= es to render content unless custom view rules are used.

Those templates can be customized by means of container- and siteaccess-= aware parameters.

= Overriding the default template for common view types

Templates for the most common view types (content/full, line, embed, or = block) can be customized by setting one the ezplatform.default.c= ontent_view_templates variables:

Controller ViewType Parameter Default value
ez_content:viewAction= full ezplatform.default_view_templates.content.= full "EzPublishCoreBundle:default:content/full.= html.twig"
ez_content:viewAction= line ezplatform.default_view_templates.content.= line "EzPublishCoreBundle:default:content/line.= html.twig"
ez_content:viewAction= embed ezplatform.default_view_temp= lates.content.embed "EzPublishCoreBundle:default= :content/embed.html.twig"
ez_page:viewAction n/a ezplatform.default_view_temp= lates.block "EzPublishCoreBundle:default= :block/block.html.twig"

Example

Add this configuration to app/config/config.yml to use app/Resources/content/view/full.html.twig as the default template = when viewing Content with the full view type:

=20
parameters:
    ezplatform.default_view_templates.content.full: "content/view/full.html=
.twig"
=20

Customizing the= default controller

The controller used to render content by default can also be changed. Th= e ezsettings.default.content_view_defaults container para= meter contains a hash that defines how content is rendered by default. It c= ontains a set of classic content view = rules for the common view types. This hash can be redefined to whatever= suits your requirements, including custom controllers, or even matchers.

Usage

View selection

To display a Content item, the ViewController uses a view manager which = selects the appropriate template depending on matching rules.

For more information about the=20 view provider configuration,=20 please refer to the dedicated section =20  .

Content view templates

A content view template is like any other template, with several specifi= c aspects.

Available variables

Variable name Type Description
location eZ\Publish\Core\Repository\Values\Conte= nt\Location The Location object. Contains meta information o= n the content (ContentInfo)
(only when accessing a Locati= on) 
content eZ\Publish\Core\Repository\= Values\Content\Content The Content item, containing all F= ields and version information (VersionInfo)
noLayout <= /code> Boolean If true, indicates if the Content = item/Location is to be displayed without any pagelayout (i.e. AJAX, sub-req= uests, etc.).
It's generally false when displaying a Conten= t item in view type full.
viewBaseLayout String The base layout template to use wh= en the view is requested to be generated outside of the pagelayout (when noLayout is true).

Template inh= eritance and sub-requests

Like any template, a content view template can use template inheritance. Ho= wever keep in mind that your content may be also requested via sub-requests (see below how to = render embedded content objects), in which case you probably don't want the= global layout to be used.

If you use different templates for embedded content views, this should n= ot be a problem. If you'd rather use the same template, you can use an extr= a noLayout view parameter for the sub-request, and condit= ionally extend an empty pagelayout:

=20
{% extends noLayout ? viewbaseLayout : "AcmeDemoBundle::pagelayout.=
html.twig" %}

{% block content %}
...
{% endblock %}
=20

Rendering Content item's Fields

As stated above, a view template receives the requested Content item, ho= lding all Fields.

In order to display the Fields' value the way you want, you can either m= anipulate the Field Value object itself, or use a custom template.

Getting raw Field value

Having access to the Content item in the template, you can use its public methods to access all the information you need. You = can also use the ez_field_value helper to get th= e field types reference . It will return the correct = language if there are several, based on language priorities.

=20
{# With the following, myFieldValue will be in the content's main l=
anguage, regardless of the current language #}
{% set myFieldValue =3D content.getFieldValue( 'some_field_identifier' ) %}
 
{# Here myTranslatedFieldValue will be in the current language if a transla=
tion is available. If not, the content's main language will be used #}
{% set myTranslatedFieldValue =3D ez_field_value( content, 'some_field_iden=
tifier' ) %}
=20

Using the Fiel= d Type's template block

All built-in Field Types come with their= own Twig template. You can render any Field using this default te= mplate using the ez_render_field() helper.

=20
{{ ez_render_field( content, 'some_field_identifier' ) }}
=20

Refer to  ez_render_field   for further information.

As this makes use of reusable templates, using ez_render_f= ield() is the recommended way and is to be considered the best pract= ice.

Rendering Content name

The name of a Content item is its generic "title", gene= rated by the repository based on the Content Type's naming pattern. It ofte= n takes the form of a normalized value of the first field, but might be a c= oncatenation of several fields. There are 2 different ways to access t= his special property:

  • Through the name property of ContentInfo (not translated).
  • Through VersionInfo with the TranslationHelper (translated).

Translated name

The translated name is held in a VersionI= nfo object, in the names property which consists of hash indexe= d by locale. You can easily retrieve it in the right language via the = TranslationHelper service.

=20
<h2>Translated content name: {{ ez_content_name( content=
 ) }}</h2>
<h3>Also works from ContentInfo : {{ ez_content_name( content.content=
Info ) }}</h3>
=20

The helper will by default follow the prioritized languages order. = If there is no translation for your prioritized languages, the helper will = always return the name in the main language.

You can also force a locale in a second argum= ent:

=20
{# Force fre-FR locale. #}
<h2>{{ ez_content_name( content, 'fre-FR' ) }}</h2>
=20

You can find more information further in this document.

Name property in Cont= entInfo

This property is the actual content name, but in main language o= nly (so it is not translated).

=20
<h2>Content name: {{ content.contentInfo.name }}</h2&=
gt;
=20
=20
$contentName =3D $content->contentInfo->name;
=20

Exposing addi= tional variables

It is possible to expose additional variables in a content view template= . See  parameters injection in content views= .

Custom controllers

In some cases, displaying a Content item/Location via the built-in ViewController is not sufficient to show everything you want. In su= ch cases you may want to use your own custom controller to= display the current Content item/Location instead.

Typical use cases include access to:

  • Settings (coming from ConfigResolver or ServiceConta= iner)
  • Current Content item's ContentType object
  • Current Location's parent
  • Current Location's children count
  • Main Location and alternative Locations for the current Content item
  • etc.

There are three ways in which you can apply a custom controller:

  • Configure a custom controller alongside regular matcher rules to use both your custom controller and the ViewController (recommended).
  • Override the built-in ViewController with= the custom controller in a specific situation.
  • Replace the ViewController with the custo= m controller for the whole bundle.

En= riching ViewController with a custom controller

This is the recommended way of using a custom controller

To use your custom controller on top of the built-in ViewControlle= r you need to point to both the controller and the template in the c= onfiguration, for example:

ezplatform.yml
=20
ezpublish:
    system:
        default:
            content_view:
                full:
                    article:
                        controller: AcmeTestBundle:Default:articleViewEnhan=
ced
                        template: AcmeTestBundle:full:article.html.twig
                        match:
                            Identifier\ContentType: [article]
=20

With this configuration, the following controller will forward the reque= st to the built-in ViewController with some additional paramet= ers:

Controller
=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. Possibly alter it (here we change the smax=
-age for cache).
        $response =3D $this->get( 'ez_content' )->viewLocation( $loca=
tionId, $viewType, $layout, $params );
        $response->setSharedMaxAge( 600 );

        return $response;
    }
}
=20

Always ensure that you add new parameters to existing $params associative array using +<= /code> union operator or array_merge(). N= ot doing so (e.g. only passing your custom parameters array) can result in = unexpected issues with content preview. Previewed content and othe= r parameters are indeed passed in $params.

These parameters can then be used in templates, for example:

article.html.twig
=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

Using only your c= ustom controller

If you want to apply only your custom controller in a given match situat= ion and not make use of the ViewController at all, in the conf= iguration you need to indicate the controller, but no template, for example= :

ezplatform.yml
=20
ezpublish:
    system:
        default:
            content_view:
                full:
                    folder:
                        controller: AcmeTestBundle:Default:viewFolder
                        match:
                            Identifier\ContentType: [folder]
                            Identifier\Section: [standard]
=20

In this example, as the ViewController is not applied, the = custom controller takes care of the whole process of displaying content, in= cluding pointing to the template to be used (in this case, AcmeTestBu= ndle::custom_controller_folder.html.twig:

Controller
=20
<?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', 'windows' )
            ) + $params
        );
    }
}
=20

Here again custom parameters can be used in the template, e.g.:

custom_controller_folder.html.twig
=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

Overriding = the built-in ViewController

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. As b= ase ViewController is defined as a service, with a service ali= as, this can be easily achieved from your bundle's configuration:

=20
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

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

Custom controller str= ucture

Your custom controller can be any kind of controller supported by Symfony (includ= ing controllers as a service)= .

The only requirement here is that your action method must have a similar= signature to ViewController::viewLocation() or ViewCont= roller::viewContent() (depending on what you're matching of course).= However, note that not all arguments are mandatory, since Symfony is clever enou= gh to know what to inject into your action method. That is why = you aren't forced to mimic the ViewController's signature stri= ctly. For example, if you omit $layout and $par= ams arguments, it will still be valid. Symfony will just avoid injec= ting them into your action method.

Built-in ViewC= ontroller signatures

viewLocation() signature
=20
/**
 * 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
viewContent() signature
=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

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

Caching

When you use your own controller, it is your responsibility to d= efine cache rules, like with every custom controller!

So don't forget to set cache rules and the appropriate = X-Location-Id header in the returned Re= sponse object.

See built-in ViewController for mor= e details on this.

Embedded images

V1.4=

The Rich Text Field allows you to embed other Content items within the F= ield.

Content items that are identified as images will be rendered in the Rich= Text Field using a dedicated template.

You can determine which Content Types will be treated as images and rend= ered using this template in the ezplatform.content_view.image_embed_c= ontent_types_identifiers parameter. By default it is set to cover th= e Image Content Type, but you can add other types that you want to be treat= ed as images, for example:

=20
parameters:
    ezplatform.content_view.image_embed_content_types_identifiers: ['image'=
, 'photo', 'banner']
=20

The template used when rendering embedded images can be set in the ezplatform.default_view_templates.content.embed_image container par= ameter:

=20
parameters:
    ezplatform.default_view_templates.content.embed_image: 'content/view/em=
bed/image.html.twig
=20

Query controller

V1.4=

The Query controller is a predefined custom content view controller that= runs a Repository Query.

It is meant to be used as a custom controller in a view configuration, a= long with match rules. It can use properties of the viewed content or locat= ion as parameters to the Query. It makes it easy to retrieve content withou= t writing custom PHP code and display the results in a template.

Use-case examples 

  • List of Blog posts in a Blog 
  • List of Images in a Gallery

Usage example

We will use the blog posts use case mentioned above as an example. It as= sumes a "Blog" container that contains a set of "Blog post" items. The goal= is, when viewing a Blog, to list the Blog posts it contains.

Three items are required:

  • a LocationChildren QueryType
    Will generate a Query= retrieving the children of a given location id
  • a View template
    Will render the Blog, and list the Blog posts it con= tains
  • content_view configuration
    Will instruct Platfor= m, when viewing a Content item of type Blog, to use the Query Controller, t= he view template, and the LocationChildren QueryType. It will also map the = id of the viewed Blog to the QueryType parameters, and set which twig varia= ble the results will be assigned to.

The LocationChildr= en QueryType

QueryTypes are described in more detail in the next section. In short, a= QueryType can build a Query object, optionally based on a set of parameter= s. The following example will build a Query that retrieves the sub-items of= a Location:

src/AppBundle/QueryType/LocationChildrenQueryType.php
=20
<?php
namespace AppBundle\QueryType;

use eZ\Publish\API\Repository\Values\Content\LocationQuery;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\ParentLocation=
Id;
use eZ\Publish\Core\QueryType\QueryType;

class LocationChildrenQueryType implements QueryType
{
    public function getQuery(array $parameters =3D [])
    {
        return new LocationQuery([
            'filter' =3D> new ParentLocationId($parameters['parentLocati=
onId']),
        ]);
    }

    public function getSupportedParameters()
    {
        return ['parentLocationId'];
    }

    public static function getName()
    {
        return 'LocationChildren';
    }
}

=20

Any class will be registered as a QueryType when it:

  • implements the QueryType interface,
  • is located in the QueryType subfolder of a bundle, and in a file named = "SomethingQueryType.php"

If the QueryType has dependencies, it can be manually tagged as a servic= e using the ezpublish.query_type service tag, but it is n= ot required in that case.

The content_view c= onfiguration

We now need a view configuration that matches content items of type "Blo= g", and uses the QueryController to fetch the blog posts:

app/config/ezplatform.yml
=20
ezpublish:
      system:
            site_group:
                content_view:
=09=09=09        full:
=09=09=09=09=09=09blog:
               =09=09    =09controller: "ez_query:locationQueryAction"
=09=09=09=09=09=09=09template: "content/view/full/blog.html.twig"
=09=09=09=09=09=09=09match:
=09=09=09=09=09=09=09=09Identifier\ContentType: "blog"
                =09=09=09params:
                            =09query:
                                =09query_type: 'LocationChildren'
                        =09=09=09parameters:
                            =09=09=09parentLocationId: "@=3Dlocation.id"
                        =09        assign_results_to: 'blog_posts'
=20

The view's controller action is set to the QueryController's locationQue= ry action (ez_query:locationQueryAction). Other actions are av= ailable that run a different type of search (contentInfo or content).

The QueryController is configured in the query ar= ray, inside the params of the content_view block:

  • query_type specifies the QueryType to use, based on its na= me.
  • parameters is a hash where parameters from the QueryType a= re set. Arbitrary values can be used, as well as properties from the curren= tly viewed location and content. In that case, the id of the currently= viewed location is mapped to the QueryType's parentLocationId parameter:  parentLocationId: "@=3Dlocation.id" <= /li>
  • assign_results_to sets which twig variable the= search results will be assigned to.

The view template<= /h4>

Results from the search are assigned to the blog_posts<= /code> variable as a SearchResult object. In addition, since t= he usual view controller is used, the currently viewed location and content are also available.

app/Resources/views/content/full/blog.html.twig
=20
<h1>{{ ez_content_name(content) }}</h1>
 
{% for blog_post in blog_posts.searchHits %}
  <h2>{{ ez_content_name(blog_post.valueObject.contentInfo) }}</h2=
>
{% endfor %} 
=20


Configuration details

controller

Three Controller Actions are available, each for a different type of sea= rch:

  • locationQueryAction runs a Location Search
  • contentQueryAction runs a Content Search
  • contentInfoQueryAction runs a Content Info search

 

See=20 Search documentation page for mor= e details about different types of search

params

The Query is configured in a query hash in params, you could specify the QueryType name, additional parameters and the Tw= ig variable that you will assign the results to for use in the template.

  • query_type

    • Name of the Query Type that will be used to run the query, defined by t= he class name.
  • parameters

    • Query Type parameters that can be provided in two ways:
    1. As scalar values, for example an identifier, an id, etc.
    2. Using the Expression language. This simple script language, similar to = Twig syntax, lets you write expressions that get value from the current con= tent and/or location:
      • For example, @=3Dlocation.id will be evaluated to the cu= rrently viewed location's ID.
        content
        , location and view are available as variables in expressions.
  • assign_results_to

    • This is the name of the Twig variable that will be assigned the results= .
    • Note that the results are the SearchResult object returned by the Searc= hService.

Query Types objects

QueryTypes are objects that build a Query. They are different from Public API queries.

To make a new QueryType available to the Query Controller, you need to c= reate a PHP class that implements the QueryType interface, then register it= as such in the Service Container.

For more information about the=20 Service Container, rea= d the page

 

Th= e QueryType interface

There you can view the PHP QueryType interface. Three methods are descri= bed:

  1. getQuery()
  2. getSupportedParameters()
  3. getName()
=20
=20 =20  Expand source= =20
=20
=20
interface QueryType
{
 /**
 * Builds and returns the Query object
 *
 * The Query can be either a Content or a Location one.
 *
 * @param array $parameters A hash of parameters that will be used to build=
 the Query
 * @return \eZ\Publish\API\Repository\Values\Content\Query
 */
 public function getQuery(array $parameters =3D []);
=20
 /**
 * Returns an array listing the parameters supported by the QueryType
 * @return array
 */
 public function getSupportedParameters();
=20
 /**
 * Returns the QueryType name
 * @return string
 */
 public static function getName();
}
=20
=20

Parameters

A QueryType may accept parameters, including string, arrays and other ty= pes, depending on the implementation. They can be used in any way, such as:=

  • customizing an element's value (limit, ContentType identifier, etc)
  • conditionally adding/removing criteria from the query
  • setting the limit/offset

The implementations should use Symfony's OptionsResolver fo= r parameters handling and resolution.

 

QueryType example: latest content

Let's see an example for a QueryType creation.

This QueryType returns a Query that searches for the 10 last published Content items, order by reverse publishing date= .
It accepts an optional type parameter, that can= be set to a ContentType identifier:

 

=20
<?php
namespace AppBundle\QueryType;
use eZ\Publish\Core\QueryType\QueryType;
use eZ\Publish\API\Repository\Values\Content\Query;
class LatestContentQueryType implements QueryType
{
    public function getQuery(array $parameters =3D [])
    {
        $criteria[] =3D new Query\Criterion\Visibility(Query\Criterion\Visi=
bility::VISIBLE);
        if (isset($parameters['type'])) {
            $criteria[] =3D new Query\Criterion\ContentTypeIdentifier($para=
meters['type']);
        }
        // 10 is the default limit we set, but you can have one defined in =
the parameters
        return new Query([
            'filter' =3D> new Query\Criterion\LogicalAnd($criteria),
            'sortClauses' =3D> [new Query\SortClause\DatePublished()],
            'limit' =3D> isset($parameters['limit']) ? $parameters['limi=
t'] : 10,
        ]);
    }
    public static function getName()
    {
        return 'AppBundle:LatestContent';
    }
    /**
     * Returns an array listing the parameters supported by the QueryType.
     * @return array
     */
    public function getSupportedParameters()
    {
        return ['type', 'limit'];
    }
}
=20

 

Namin= g of QueryTypes

Each QueryType is named after what is returned by getName()= . Names must be unique. A warning will be thrown during co= mpilation if there is a conflict, and the resulting behavior will be unpred= ictable.

QueryType names should use a unique namespace, in order to avoid conflic= ts with other bundles. We recommend that the name is prefixed with the bund= le's name: AcmeBundle:LatestContent. A vendor/company's name c= ould also work for QueryTypes that are reusable throughout projects: = Acme:LatestContent.

= Registering the QueryType into the service container=

In addition to creating a class for a QueryType, you must a= lso register the QueryType with the Service Container. This can be done in = two ways: by convention, and with a service tag.

By conventi= on

Any class named <Bundle>\QueryType\*QueryType, that i= mplements the QueryType interface, will be registered as a custom QueryType= .
Example: AppBundle\QueryType\LatestContentQueryType.

Using a= service tag

If the proposed convention doesn't work for you, QueryTypes can be manua= lly tagged in the service declaration:

=20
acme.query.latest_content:
    class: AppBundle\Query\LatestContent
    tags:
        - {name: ezpublish.query_type}
=20

The effect is exactly the same than registering by convention.

More content...

Follow the FieldType creation Tutorial and learn how to Register the Field Type= as a service

<= span class=3D"anchor">The OptionsResolverBasedQueryType abstract class

An abstract class based on Symfony's OptionsResolver eases = implementation of QueryTypes with parameters.

It provides final implementations of getQuery() and g= etDefinedParameters().

A doGetQuery() method must be implemented instead of = getQuery(). It is called with the parameters processed by the Option= sResolver, meaning that the values have been validated, and default values = have been set.

In addition, the configureOptions(OptionsResolver $resolver) method must configure the OptionsResolver.

The LatestContentQueryType can benefit from the abstract implementation:=

  • validate that type is a string, but make it optional
  • validate that limit is an int, with a default value of 10<= /li>

 

For further information see the=20 Symfony's Options Resolver docume= ntation page
=20
<?php
namespace AppBundle\QueryType;
use eZ\Publish\API\Repository\Values\Content\Query;
use Symfony\Component\OptionsResolver\OptionsResolver;
class OptionsBasedLatestContentQueryType extends OptionsResolverBasedQueryT=
ype implements QueryType
{
    protected function doGetQuery(array $parameters)
    {
        $criteria[] =3D new Query\Criterion\Visibility(Query\Criterion\Visi=
bility::VISIBLE);
        if (isset($parameters['type'])) {
            $criteria[] =3D new Query\Criterion\ContentTypeIdentifier($para=
meters['type']);
        }
        return new Query([
            'criterion' =3D> new Query\Criterion\LogicalAnd($criteria),
            'sortClauses' =3D> [new Query\SortClause\DatePublished()],
            'limit' =3D> $parameters,
        ]);
    }
    public static function getName()
    {
        return 'AppBundle:LatestContent';
    }
    protected function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setAllowedTypes('type', 'string');
        $resolver->setAllowedValues('limit', 'int');
        $resolver->setDefault('limit', 10);
    }
}
=20

Using QueryTypes from PHP code

All QueryTypes are registered in a registry, the QueryType registry.

It is available from the container as ezpublish.query_type.registr= y

=20
<?php
class MyCommand extends ContainerAwareCommand
{
    protected function execute(InputInterface $input, OutputInterface $outp=
ut)
    {
        $queryType     =3D $this->getContainer()->get('ezpublish.quer=
y_type.registry')->getQueryType('AcmeBundle:LatestContent');
        $query         =3D $queryType->getQuery(['type' =3D> 'article=
']);
        $searchResults =3D $this->getContainer()->get('ezpublish.api.=
service.search')->findContent($query);
        foreach ($searchResults->searchHits as $searchHit) {
            $output->writeln($searchHit->valueObject->contentInfo-=
>name);
        }
    }
}

=20

Making links to oth= er locations

Linking to other locations is fairly easy and is done with a native path() Twig helper= (or url() if you want to generate absolute URLs). You jus= t have to pass it the Location object and path() will generate= the URLAlias for you.

=20
{# Assuming "location" variable is a valid eZ\Publish\API\Repositor=
y\Values\Content\Location object #}
<a href=3D"{{ path( location ) }}">Some link to a location</a><=
/pre>=20

If you don't have the Location object, but only its ID, you can generate= the URLAlias the following way:

=20
<a href=3D"{{ path( "ez_urlalias", {"locationId": 123} ) }}">=
Some link to a location, with its Id only</a>
=20

You can also use the Content ID. In that case the generated link will po= int to the Content item's main Location.

=20
<a href=3D"{{ path( "ez_urlalias", {"contentId": 456} ) }}">S=
ome link from a contentId</a>
=20

Under the hood

In the backend, path() uses the Router to generate links.

This makes it also easy to generate links from PHP, via the router= service.

See also: Cross-siteaccess links

Render embedded co= ntent objects

Rendering an embedded content from a Twig template is pretty straight fo= rward as you just need to do a subrequest with ez_content controller.

Using ez_c= ontent controller

This controller is exactly the same as the ViewController presented above. It has one main=  viewAction, that renders a Content item.

You can use this controller from templates with the following syntax:

=20
{{ render(controller("ez_content:viewAction", {"contentId": 123, "v=
iewType": "line"})) }}
=20

The example above renders the Content whose ID is 123, = with the view type line.

Reference of ez_content controller follows the syntax of controllers as a service, = as explained in Symfony documentation.

Available arguments

As with any controller, you can pass arguments to ez_content:viewL= ocation or ez_content:viewContent to fit your needs.

Name Description Type Default value
contentId

ID of the Content item you want to render. Only for ez_content:viewContent  

<= /td>
integer N/A
locationId ID of the Location you want to render.
Only for ez_content:viewLocation  
integer Content item's main location, if d= efined
viewType

The view type you want to rende= r your Content item/Location in.
Will be used by the ViewManager to sele= ct a corresponding template, according to defined rules. 

Exampl= e: full, line, my_custom_view, etc.

string full
layout

Indicates if the sub-view needs= to use the main layout (see   = available variables in a view template )

 

=
boolean false
params

Hash of variables you want to i= nject to sub-template, key being the exposed variable name.

=20
{{ render(
      controller( 
          "ez_content:viewAction", 
          {
              "contentId": 123,
              "viewType": "line",
              "params": { "some_variable": "some_value" }
          }
      )
) }}
=20
hash empty hash

Render block

You can specify which controller will be called for a specific block vie= w match, much like defining custom controllers for location view or content= view match.

Also, since there are two possible actions with which one can view a blo= ck: ez_page:viewBlock and ez_page:viewBlockById, = it is possible to specify a controller action with a signature matching eit= her one of the original actions.

Example of configuration in app/config/ezplatform.yml:

=20
ezpublish:
    system:
        eng_frontend_group:
            block_view:
                ContentGrid:
                    template: NetgenSiteBundle:block:content_grid.html.twig
                    controller: NetgenSiteBundle:Block:viewContentGridBlock
                    match:
                        Type: ContentGrid
=20

ESI

Just as for regular Symfony controllers, you can take advantage of ESI a= nd use different cache levels:

Using ESI
=20
{{ render_esi(controller("ez_content:viewAction", {"contentId": 123=
, "viewType": "line"})) }}
=20

Only scalable variables can be sent via render_esi (not object)

 

Asynchronous rendering

Symfony also supports asynchronous content rendering with the help of&nb= sp;hinclude.js library.

Asynchronous rendering
=20
{{ render_hinclude(controller("ez_content:viewAction", {"contentId"=
: 123, "viewType": "line"})) }}
=20

Only scalable variables can be sent via render_hinclude (not object)

Display a default text

If you want to display a default text while a controller is loaded async= hronously, you have to pass a second parameter to your render_hinclude twig= function.

Display a default text during asynchronous loading of a controller
=20
{{ render_hinclude(controller('EzCorporateDesignBundle:Header:userL=
inks'), {'default': "<div style=3D'color:red'>loading</div>"}) =
}}
=20

See also: Custom control= lers

hinclude.js needs to be properly included in your layout = to work.

Please refer to Symfony documentation for all available options.

Content and Loc= ation view providers

View\Manager &am= p; View\Provider

The role of the (eZ\Publish\Core\MVC\Symfony\)View\Manager<= /span>  is to select the right template for displaying a given = content item or location. It aggregates objects called content and loca= tion view providers which respectively implement eZ\Pu= blish\Core\MVC\Symfony\View\Provider\Content and eZ\= Publish\Core\MVC\Symfony\View\Provider\Location interfaces.

Each time a content item is to be displayed through the Content\Vi= ewController, the View\Manager iterates over the regist= ered content or location View\Provider objects and calls&= nbsp;getView ().

Provided V= iew\Provider implementations

Name Usage
View provider configuratio= n

Based on application configuration.
Former= ly known as Template override system.

eZ\Publish\Core\MVC\Legacy\View\Provide= r\Content

eZ\Publish\Core\MVC\Legacy\View\Provider\Locat= ion

Forwards view selection to the legacy kernel = by running the old content/view module.
Pagelayout used is the one confi= gured in ezpublish_legacy.<scope>.view_default_layout.For more details about the <scope> please refer to the= scope configuration documentation.

Custom View\Provider

Difference between View\Provider\Location and View\Provider\Content

  • View\Provider\Location only deals with Location objects and implements eZ\Publish\Core\= MVC\Symfony\View\Provider\Location interface.
  • View\Provider\Content only deals with ContentInfo objects and implements eZ\Publish\Cor= e\MVC\Symfony\View\Provider\Content interface.

When to develop a custom View\Provider\(Location|Content)

  • You want a custom template selection based on a very specific state of = your application
  • You depend on external resources for view selection
  • You want to override the default one (based on configuration) for some = reason

View\Provider objects need to be properly registered in the= service container with the ezpublish.location_view_provider= or  ezpublish.content_view_provider  service tag.

=20
parameters:
    acme.location_view_provider.class: Acme\DemoBundle\Content\MyLocationVi=
ewProvider

services:
    acme.location_view_provider:
        class: %ezdemo.location_view_provider.class%
        tags:
            - {name: ezpublish.location_view_provider, priority: 30}

=20
Tag attribute name Usage
priority

An integer giving the priority to the = View\Provider\(Content|Location) in the View\Man= ager.

The priority range is from -255 to 255<= /p>

Example

Custom View\Provider\Location
=20
<?php

namespace Acme\DemoBundle\Content;

use eZ\Publish\Core\MVC\Symfony\View\ContentView;
use eZ\Publish\Core\MVC\Symfony\View\Provider\Location as LocationViewProvi=
der;
use eZ\Publish\API\Repository\Values\Content\Location;

class MyLocationViewProvider implements LocationViewProvider
{
    /**
     * Returns a ContentView object corresponding to $location, or void if =
not applicable
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
     * @param string $viewType
     * @return \eZ\Publish\Core\MVC\Symfony\View\ContentView|null
     */
    public function getView( Location $location, $viewType )
    {
        // Let's check location Id
        switch ( $location->id )
        {
            // Special template for home page, passing "foo" variable to th=
e template
            case 2:
                return new ContentView( "AcmeDemoBundle:$viewType:home.html=
.twig", array( 'foo' =3D> 'bar' ) );
        }
 
        // ContentType identifier (formerly "class identifier")
        switch ( $location->contentInfo->contentType->identifier )
        {
            // For view full, it will load AcmeDemoBundle:full:small_folder=
.html.twig
            case 'folder':
                return new ContentView( "AcmeDemoBundle:$viewType:small_fol=
der.html.twig" );
        }
    }
}
=20

Binary and Media downloa= d

Unlike image files, files stored in BinaryFile or Media Fields may be li= mited to certain User Roles. As such, they are not publicly downloadable fr= om disk, and are instead served by Symfony, using a custom route that = runs the necessary checks. This route is automatically generated as the&nbs= p;url property for those Fields values.

The content/download r= oute

The route follows this pattern: /content/download/{contentId}= /{fieldIdentifier}/{filename}. Example: /content/dow= nload/68/file/My-file.pdf.

It also accepts optional query parameters:

  • versionthe version number that the file must = be downloaded for. Requires the versionview permission. If not specified, t= he published version is used.
  • inLanguageThe language the file should be dow= nloaded in. If not specified, the most prioritized language for the siteacc= ess will be used.

The  ez_render_field  twig helper will by default generate a working link.

REST API: The `uri` property contains a valid download URL

The uri property of Binary Fields in REST contain a valid U= RL, of the same format than the Public API, prefixed with the same host tha= n the REST Request.

Reference

Symfony & Twig template functions/filters/tags

For template functionality provided by Symfony Framework, see Symfony Twig Extensions Reference page. Fo= r those provided by the underlying Twig template engine, see Twig Reference page

Twig functions reference=

See Twig Functio= ns Reference for detailed information on all available Twig functions.<= /p>

Extensibility

Events

Introduction

This page presents the events that are triggered by eZ Platform.

eZ Publish Core

Event name Triggered when... Usage
ezpublish.siteacces= s After the SiteAccess matching has = occurred.

Gives further control on the ma= tched SiteAccess.

The event listener method receives an eZ\Publ= ish\Core\MVC\Symfony\Event\PostSiteAccessMatchEvent object.

=
ezpublish.pre_conte= nt_view Right before a view is rendered fo= r a content item, via the content view controller.

This event is triggered by the = view manager and allows you to inject additional parameters to the content = view template.

The event listener method receives an eZ\Publish\Core\MVC\Symfony\Event\PreContentViewEvent object.

&nbs= p;

ezpublish.api.conte= ntException The API throws an exception that c= ould not be caught internally (missing field type, internal error...).

This event allows further progr= ammatic handling (like rendering a custom view) for the exception thrown.

The event listener method receives an eZ\Publish\Core\MVC\Symfony\Event\APIContentExceptionEvent object.

=20
=20
=20
=20

In this topic:

Related topics:

Inj= ecting parameters in content views

=20
=20
=20
------=_Part_2741_1338822572.1485850606311--