While creating this blog, I've used the latest version of eZ Platform, introducing "QueryTypes" (available from version 1.0, but starting to be awesome as of 1.6), and this feature really rocks!
I remember when I was studying computer science in college (ten years ago, aouch!), my professor told us that in a few years, developers may disappear in favor of software architects.
With this QueryType feature, it starts to become a reality! You don't need to write PHP code anymore (well, still a little) in order to inject required variables into a template. That's a good start for simplifying most of your dev tasks while creating a webapp.
When you need to display a "folder" content with its children, you need to enrich the business logic by adding your own logic, in order to fetch children using a PHP Query and inject the SearchResult into your template.
Something like that:
ezpublish:
system:
eng:
content_view:
full:
folder:
controller: AcmeDemoBundle:Folder:getChildren
template: "@ezdesign/full/folder.html.twig"
match:
Identifier\ContentType: ["folder"]
You also need to create the dedicated PHP action to get all existing children.
<pre><?php
namespace Acme\DemoBundle\Controller;
use eZ\Bundle\EzPublishCoreBundle\Controller;
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
use eZ\Publish\API\Repository\Values\Content\Query;
use Symfony\Component\HttpFoundation\Response
class FolderController extends Controller
{
public function getChildrenAction(int $locationId, string $viewType, string $layout, array $params):Response
{
$repository = $this->getRepository();
$locationService = $repository->getLocationService();
$contentService = $repository->getContentService();
$folderLocation = $locationService->loadLocation($locationId);
$query = new LocationQuery();
$query->criterion = new Criterion\LogicalAnd([
new Criterion\Subtree([$folderLocation->pathString]),
new Criterion\ContentTypeIdentifier( 'article' )
]);
$query->sortClauses = [
new SortClause\Location\Priority(Query::SORT_DESC)
];
$children = $repository->getSearchService()->findLocations($query);
$params += ['children' => $children];
return $this->get( 'ez_content' )->viewLocation($locationId, $viewType, $layout, $params);
}
}</pre>
And the dedicated template.
<pre>{% extends "@ezdesign/pagelayout.html.twig" %}
{% block content %}
{% for child in children.searchHits %}
{{ ez_content_name(child.valueObject.contentInfo) }}
{% endfor %}
{% endblock %}</pre>
As you can see, there is a lot of (non-reusable) PHP code, only to inject article children into your template. And it's a hard work to design this action generic enough for all kind of children (e.g. blog with blog_post?).
Tips: A good workaround would be to use the parameter provider feature from the EzCoreExtraBundle (paramProvider are reusable across multiple override rules).
But, let's focus QueryTypes.
Thanks to Bertrand Dunogier, QueryTypes ease designing websites using only Yaml configuration files and templates.
Let's do the same as above but with QueryType this time.
You will need an override rule, a template and a generic PHP fetcher (that will be common and reusable in your override rules).
ezpublish:
system:
eng:
content_view:
full:
folder:
controller: "ez_query:contentQueryAction"
template: "@ezdesign/full/folder.html.twig"
match:
Identifier\ContentType: ["folder"]
params:
query:
query_type: "CRParameterProvider:GetChildren"
parameters:
parentLocationId: "@=location.id"
type: ["article"]
assign_results_to: "children"
Then just create a generic children "fetcher" query type:
<pre><?php
namespace CR\Bundles\ParameterProviderBundle\QueryType;
use eZ\Publish\Core\QueryType\QueryType;
use eZ\Publish\API\Repository\Values\Content\Query;
class GetChildrenQueryType implements QueryType
{
public function getQuery(array $parameters = [])
{
$criteria = [
new Query\Criterion\Visibility(Query\Criterion\Visibility::VISIBLE)
];
if (isset($parameters['parentLocationId'])) {
$criteria[] = new Query\Criterion\ParentLocationId($parameters['parentLocationId']);
}
if (isset($parameters['type'])) {
$criteria[] = new Query\Criterion\ContentTypeIdentifier($parameters['type']);
}
if (isset($parameters['relatedContentIds'])) {
$criteria[] = new Query\Criterion\ContentId($parameters['relatedContentIds']);
}
// 10 is the default limit we set, but you can have one defined in the parameters
return new Query([
'filter' => new Query\Criterion\LogicalAnd($criteria),
'sortClauses' => [new Query\SortClause\DatePublished(Query::SORT_ASC)],
'limit' => $parameters['limit'] ?? 10,
]);
}
public static function getName()
{
return 'CRParameterProvider:GetChildren';
}
/**
* Returns an array listing the parameters supported by the QueryType.
* @return array
*/
public function getSupportedParameters()
{
return ['parentLocationId', 'type', 'relatedContentIds', 'limit'];
}
}</pre>
And then, you just need to reuse this configuration for all your next override rules by changing the parameters sent to the query.
If you need to inject related contents from an Object Relations field, use the expression language like this :
# ...
query:
queryType: "CRParameterProvider:GetChildren"
parameters:
relatedContentIds: "@=content.getFieldValue('related_content').destinationContentIds"
QueryTypes open doors and create opportunities for future developments, but as you can see, you can only have one query injecting a variable into a template.
One possible improvement would be to allow multiple queries. That way we'd be able to add as many result sets as needed, like for override rules. For example:
ezpublish:
system:
eng:
location_view:
full:
folder:
controller: "ez_query:contentQueryAction"
template: "@ezdesign/full/folder.html.twig"
match:
Identifier\ContentType: "folder"
params:
query:
<strong>article_children</strong>:
query_type: "CRParameterProvider:GetChildren"
parameters:
parentLocationId: "@=location.id"
type: ["article"]
assign_results: "children"
<strong>other_result_set</strong>:
query_type: "CRParameterProvider:GetChildrenBis"
parameters:
parentLocationId: "@=location.id"
type: ["sausage"]
assign_results: "sausages"
Use it and feel free to comment this article and give us some feedback, I'm pretty sure that you will change your mind when using eZ Platform for website development.
Cheers ;)
To celebrate the release of Dataflow 5 for Symfony 7, here is some feedback on ...
🎯 Nous relevons le défi de lancer un grand concours : Vous faire gagner un ...
How to dynamically calculate shipping costs? The official documentation that explains how to create shipping ...
How to create a new product attribute type in Ibexa Commerce
A la recherche d'un poste de travail temporaire ou permanent ? Vous recherchez un environnement ...
Après une découverte de surface d'Ibexa Commerce, entrons plus dans le détail pour comprendre son ...
Ibexa DXP propose un module pour gérer des produits pour la réalisation d'un site e-commerce. ...
Voici une présentation d'IbexaMailing, un module qui ajoute la gestion des newsletters à Ibexa. IbexaMailing est ...
C'est la dernière occasion de vous souhaitez le meilleur pour cette année 2024 et surtout ...
To celebrate the release of Dataflow 5 for Symfony 7, here is some feedback on ...
🎯 Nous relevons le défi de lancer un grand concours : Vous faire gagner un ...
How to dynamically calculate shipping costs? The official documentation that explains how to create shipping ...
How to create a new product attribute type in Ibexa Commerce
A la recherche d'un poste de travail temporaire ou permanent ? Vous recherchez un environnement ...
Après une découverte de surface d'Ibexa Commerce, entrons plus dans le détail pour comprendre son ...
Ibexa DXP propose un module pour gérer des produits pour la réalisation d'un site e-commerce. ...
Voici une présentation d'IbexaMailing, un module qui ajoute la gestion des newsletters à Ibexa. IbexaMailing est ...
C'est la dernière occasion de vous souhaitez le meilleur pour cette année 2024 et surtout ...