Controllers¶
Custom rendering logic¶
In some cases, displaying a Content item/Location via the built-in ViewController is not sufficient to show everything you want. In such cases you may want to use your own custom logic to display the current Content item/Location instead.
Typical use cases include access to:
- Settings (coming from 
ConfigResolverorServiceContainer) - Current Content item's 
ContentTypeobject - 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 logic:
- Configure a custom view controller alongside regular matcher rules (recommended).
 - Add a Symfony Response listener to add custom logic to all responses.
 - Override the built-in 
ViewControllerwith the custom controller in a specific situation. 
Permissions for custom controllers
See permission documentation for information about access control for custom controllers.
Enriching 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 ViewController you need to point to both the controller and the template in the configuration, for example:
1 2 3 4 5 6 7 8 9 10 11  |  | 
With this configuration, the following controller will forward the request to the built-in ViewController with some additional parameters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28  |  | 
These parameters can then be used in templates, for example:
1 2 3 4 5 6 7 8  |  | 
Adding a listener¶
One way to add custom logic to all responses is to use your own listener. Please refer to the Symfony documentation for the details on how to achieve this.
Using only your custom controller¶
If you want to apply only your custom controller in a given match situation and not use the ViewController at all, in the configuration you need to indicate the controller, but no template, for example:
1 2 3 4 5 6 7 8 9 10 11  |  | 
In this example, as the ViewController is not applied, the custom controller takes care of the whole process of displaying content, including pointing to the template to be used (in this case, AcmeTestBundle::custom_controller_folder.html.twig):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  |  | 
Here again custom parameters can be used in the template, e.g.:
1 2 3 4 5 6 7 8 9 10 11 12  |  | 
Query controller¶
The Query controller is a predefined custom content view controller that runs a repository Query.
You can use it as a custom controller in a view configuration, alongside match rules. It can use properties of the viewed Content item or Location as parameters to the Query.
The Query controller makes it easy to retrieve content without writing custom PHP code and to display the results in a template. Example use cases include:
- List of Blog posts in a Blog
 - List of Images in a Gallery
 
Usage example¶
This example assumes 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 
LocationChildrenQueryType - It will generate a Query retrieving the children of a given Location id - a View template - It will render the Blog, and list the Blog posts it contains
 - a 
content_viewconfiguration - It will instruct Platform, when viewing a Content item of type Blog, to use the Query Controller, the view template, and theLocationChildrenQueryType. It will also map the id of the viewed Blog to the QueryType parameters, and set which Twig variable the results will be assigned to. 
The LocationChildren 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 parameters. The following example will build a Query that retrieves the sub-items of a Location:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27  |  | 
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 
<Something>QueryType.php. 
If the QueryType has dependencies, it can be manually tagged as a service using the ezpublish.query_type service tag, but it is not required in that case.
The content_view configuration¶
We now need a view configuration that matches Content items of type "Blog", and uses the QueryController to fetch the blog posts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  |  | 
The view's controller action is set to the QueryController's locationQuery action (ez_query:locationQueryAction). Other actions are available that run a different type of search (contentInfo or content).
The QueryController is configured in the query array, inside the params of the content_view block:
query_typespecifies the QueryType to use, based on its name.parametersis a hash where parameters from the QueryType are set. Arbitrary values can be used, as well as properties from the currently viewed Location and ContentInfo. In that case, the id of the currently viewed Location is mapped to the QueryType'sparentLocationIdparameter:parentLocationId: "@=location.id"assign_results_tosets which Twig variable the search results will be assigned to.
The view template¶
Results from the search are assigned to the blog_posts variable as a SearchResult object. In addition, since the standard ViewController is used, the currently viewed location and content are also available.
1 2 3 4 5 6  |  | 
Configuration details¶
controller¶
Three Controller Actions are available, each for a different type of search:
locationQueryActionruns a Location SearchcontentQueryActionruns a Content SearchcontentInfoQueryActionruns a Content Info search
See the Search documentation page for more 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 Twig 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 the class name.parameters- Query Type parameters that can be provided in two ways: 1. As scalar values, for example an identifier, an id, etc. 1. Using the Expression language. This simple script language, similar to Twig syntax, lets you write expressions that get value from the current Content and/or Location: - For example,@=location.idwill be evaluated to the currently viewed location's ID.content,locationandvieware 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 SearchService.
 
QueryType objects¶
QueryType is an object that build a Query. It is different from public PHP API queries.
To make a new QueryType available to the Query Controller, you need to create a PHP class that implements the QueryType interface, then register it as such in the Service Container.
For more information about the Service Container on its documentation page.
The QueryType interface¶
The PHP QueryType interface describes three methods:
getQuery()getSupportedParameters()getName()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  |  | 
Parameters¶
A QueryType may accept parameters, including string, array and other types, 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 for parameter handling and resolution.
QueryType example: latest content¶
This QueryType returns a Query that searches for the 10 last published Content items, ordered by reverse publishing date.
It accepts an optional type parameter that can be set to a ContentType identifier:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32  |  | 
Naming of QueryTypes¶
Each QueryType is named after what is returned by getName(). Names must be unique. A warning will be thrown during compilation if there is a conflict, and the resulting behavior will be unpredictable.
QueryType names should use a unique namespace, in order to avoid conflicts with other bundles. We recommend that the name is prefixed with the bundle's name, e.g.: AcmeBundle:LatestContent. A vendor/company's name could also work for QueryTypes that are reusable throughout projects, e.g.: Acme:LatestContent.
Registering the QueryType into the service container¶
In addition to creating a class for a QueryType, you must also register the QueryType with the Service Container. This can be done in two ways: by convention, and with a service tag.
By convention¶
Any class named <Bundle>\QueryType\*QueryType that implements 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 manually tagged in the service declaration:
1 2 3 4  |  | 
The effect is exactly the same as when registering by convention.
More information
Follow the FieldType creation Tutorial and learn how to Register the Field Type as a service.
The OptionsResolverBasedQueryType abstract class¶
An abstract class based on Symfony's OptionsResolver makes the implementation of QueryTypes with parameters easier.
It provides final implementations of getQuery() and getDefinedParameters().
A doGetQuery() method must be implemented instead of getQuery(). It is called with the parameters processed by the OptionsResolver, 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 from the example above can benefit from the abstract implementation:
- validate that 
typeis a string, but make it optional - validate that 
limitis an int, with a default value of 10 
Note
For further information see the Symfony's Options Resolver documentation page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42  |  | 
Using QueryTypes from PHP code¶
All QueryTypes are registered in the QueryType registry.
It is available from the container as ezpublish.query_type.registry.
1 2 3 4 5 6 7 8 9 10 11 12 13  |  |