Before Ibexa 3, a great way to inject variables into content view templates was to use eZCoreExtraBundle ParameterProvider. Now, with Ibexa 3, there is a way to do the same without the need for a third party bundle.
As an example, let's write a VariableProvider that loads all contents from one relation list field of our viewed content. (example code for PHP 7.4+)
<?php
declare(strict_types=1);
namespace App\Provider;
use ArrayObject;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\Core\FieldType\RelationList;
use eZ\Publish\Core\MVC\Symfony\View\ContentView;
use eZ\Publish\Core\MVC\Symfony\View\View;
use eZ\Publish\SPI\MVC\View\VariableProvider;
class RelatedVariableProvider implements VariableProvider
{
private ContentService $contentService;
public function __construct(ContentService $contentService)
{
$this->contentService = $contentService;
}
public function getIdentifier(): string
{
// Will be used in config
return 'related';
}
public function getTwigVariables(View $view, array $options = []): object
{
/** @var ContentView $view */
$content = $view->getContent();
/** @var RelationList\Value $value */
$value = $content->getFieldValue('media');
// Return value is typed object, so we simple use ArrayObject
return new ArrayObject(array_map(
fn (int $contentId) => $this->contentService->loadContent($contentId),
$value->destinationContentIds
));
}
}
Now, let's add it in our view configuration:
ezplatform:
system:
default:
content_view:
full:
article:
template: "@ezdesign/content/full/article.html.twig"
match:
Identifier\ContentType: article
params:
# Calling the VariableProvider is done by the ExpressionLanguage
medias: '@=twig_variable_provider("related")'
Ok, but what if I want to choose the field identifier? Sadly, unlike ParameterProvider, it's not possible to pass options directly (twig_variable_provider accepts only one argument: the provider identifier). But, since the VariableProvider is called through the ExpressionLanguage, we can call a method on the VariableProvider return value, with any argument we want.
Let's change our VariableProvider a bit:
<?php
declare(strict_types=1);
namespace App\Provider;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\Core\FieldType\RelationList;
use eZ\Publish\Core\MVC\Symfony\View\ContentView;
use eZ\Publish\Core\MVC\Symfony\View\View;
use eZ\Publish\SPI\MVC\View\VariableProvider;
class RelatedVariableProvider implements VariableProvider
{
private ContentService $contentService;
public function __construct(ContentService $contentService)
{
$this->contentService = $contentService;
}
public function getIdentifier(): string
{
return 'related';
}
public function getTwigVariables(View $view, array $options = []): object
{
return $this;
}
public function load(View $view, string $fieldIdentifier): array
{
/** @var ContentView $view */
$content = $view->getContent();
/** @var RelationList\Value $value */
$value = $content->getFieldValue($fieldIdentifier);
return array_map(
fn(int $contentId) => $this->contentService->loadContent($contentId),
$value->destinationContentIds
);
}
}
The getTwigVariables method will simply return the provider itself, so we can call any method on it in the expression.
Let's change our view configuration accordingly:
ezplatform:
system:
default:
content_view:
full:
article:
template: "@ezdesign/content/full/article.html.twig"
match: Identifier\ContentType: article
params:
# Calling the VariableProvider is done by the ExpressionLanguage
medias: '@=twig_variable_provider("related").load(view, "media")'
Let's see what our example would look like as a ParameterProvider, and list the differences:
<?php
declare(strict_types=1);
namespace App\Provider;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\Core\FieldType\RelationList;
use eZ\Publish\Core\MVC\Symfony\View\ContentView;
use Lolautruche\EzCoreExtraBundle\View\ConfigurableView;
use Lolautruche\EzCoreExtraBundle\View\ViewParameterProviderInterface;
class RelatedParameterProvider implements ViewParameterProviderInterface
{
private ContentService $contentService;
public function __construct(ContentService $contentService)
{
$this->contentService = $contentService;
}
public function getViewParameters(ConfigurableView $view, array $options = [])
{
/** @var ContentView $view */
$content = $view->getContent();
/** @var RelationList\Value $value */
$value = $content->getFieldValue($options['field_identifier']);
return array_map(
fn(int $contentId) => $this->contentService->loadContent($contentId),
$value->destinationContentIds
);
}
}
The view configuration:
ezplatform:
system:
default:
content_view:
full:
article:
template: "@ezdesign/content/full/article.html.twig"
match: Identifier\ContentType: article
params:
medias:
provider: related
options:
field_identifier: media
And the service configuration (assuming autowiring and autoconfiguration are enabled):
services:
App\Provider\RelatedParameterProvider:
tags:
- { name: "ez_core_extra.view_parameter_provider", alias: "related" }
To migrate that ParameterProvider: