Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-9415: Added support for ContentAwareInterface in ibexa_* Twig functions #467

Open
wants to merge 9 commits into
base: 4.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 91 additions & 30 deletions src/lib/MVC/Symfony/Templating/Twig/Extension/ContentExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
use Ibexa\Contracts\Core\Repository\Values\Content\Field;
use Ibexa\Contracts\Core\Repository\Values\ValueObject;
Expand Down Expand Up @@ -137,69 +138,70 @@ public function getFunctions(): array
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\ValueObject $content Must be a valid Content or ContentInfo object.
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data Must be a valid Content, ContentInfo, or ContentAwareInterface object.
* @param string $forcedLanguage Locale we want the content name translation in (e.g. "fre-FR"). Null by default (takes current locale)
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType When $content is not a valid Content or ContentInfo object.
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType When $content is not a valid Content, ContentInfo, or ContentAwareInterface object.
*
* @return string
*/
public function getTranslatedContentName(ValueObject $content, $forcedLanguage = null)
public function getTranslatedContentName(object $data, $forcedLanguage = null)
{
$content = $this->resolveData($data);
if ($content instanceof Content) {
return $this->translationHelper->getTranslatedContentName($content, $forcedLanguage);
} elseif ($content instanceof ContentInfo) {
return $this->translationHelper->getTranslatedContentNameByContentInfo($content, $forcedLanguage);
}

throw new InvalidArgumentType(
'$content',
sprintf('%s or %s', Content::class, ContentInfo::class),
$content
'$data',
sprintf('%s or %s or %s', Content::class, ContentInfo::class, ContentAwareInterface::class),
$data
);
}

/**
* Returns the translated field, very similar to getTranslatedFieldValue but this returns the whole field.
* To be used with ibexa_image_alias for example, which requires the whole field.
*
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
* @param string $fieldDefIdentifier Identifier for the field we want to get.
* @param string $forcedLanguage Locale we want the field in (e.g. "cro-HR"). Null by default (takes current locale).
*
* @return \Ibexa\Contracts\Core\Repository\Values\Content\Field
*/
public function getTranslatedField(Content $content, $fieldDefIdentifier, $forcedLanguage = null)
public function getTranslatedField(object $data, $fieldDefIdentifier, $forcedLanguage = null)
{
return $this->translationHelper->getTranslatedField($content, $fieldDefIdentifier, $forcedLanguage);
return $this->translationHelper->getTranslatedField($this->getContent($data), $fieldDefIdentifier, $forcedLanguage);
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
* @param string $fieldDefIdentifier Identifier for the field we want to get the value from.
* @param string $forcedLanguage Locale we want the content name translation in (e.g. "fre-FR"). Null by default (takes current locale).
*
* @return mixed A primitive type or a field type Value object depending on the field type.
*/
public function getTranslatedFieldValue(Content $content, $fieldDefIdentifier, $forcedLanguage = null)
public function getTranslatedFieldValue(object $data, $fieldDefIdentifier, $forcedLanguage = null)
{
return $this->translationHelper->getTranslatedField($content, $fieldDefIdentifier, $forcedLanguage)->value;
return $this->translationHelper->getTranslatedField($this->getContent($data), $fieldDefIdentifier, $forcedLanguage)->value;
}

/**
* Gets name of a FieldDefinition name by loading ContentType based on Content/ContentInfo object.
* Gets name of a FieldDefinition name by loading ContentType based on Content/ContentInfo/ContentAwareInterface object.
*
* @param \Ibexa\Contracts\Core\Repository\Values\ValueObject $content Must be Content or ContentInfo object
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data Must be Content, ContentInfo, or ContentAwareInterface object
* @param string $fieldDefIdentifier Identifier for the field we want to get the name from
* @param string $forcedLanguage Locale we want the content name translation in (e.g. "fre-FR"). Null by default (takes current locale)
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType When $content is not a valid Content object.
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType When $content is not a valid Content, ContentInfo, or ContentAwareInterface object.
*
* @return string|null
*/
public function getTranslatedFieldDefinitionName(ValueObject $content, $fieldDefIdentifier, $forcedLanguage = null)
public function getTranslatedFieldDefinitionName(object $data, $fieldDefIdentifier, $forcedLanguage = null)
{
if ($contentType = $this->getContentType($content)) {
if ($contentType = $this->getContentType($this->resolveData($data))) {
return $this->translationHelper->getTranslatedFieldDefinitionProperty(
$contentType,
$fieldDefIdentifier,
Expand All @@ -208,23 +210,25 @@ public function getTranslatedFieldDefinitionName(ValueObject $content, $fieldDef
);
}

throw new InvalidArgumentType('$content', 'Content|ContentInfo', $content);
throw new InvalidArgumentType(
'$data',
sprintf('%s or %s or %s', Content::class, ContentInfo::class, ContentAwareInterface::class),
$data
);
}

/**
* Gets name of a FieldDefinition description by loading ContentType based on Content/ContentInfo object.
* Gets name of a FieldDefinition description by loading ContentType based on Content/ContentInfo/ContentAwareInterface object.
*
* @param \Ibexa\Contracts\Core\Repository\Values\ValueObject $content Must be Content or ContentInfo object
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data Must be Content, ContentInfo, or ContentAwareInterface object
* @param string $fieldDefIdentifier Identifier for the field we want to get the name from
* @param string $forcedLanguage Locale we want the content name translation in (e.g. "fre-FR"). Null by default (takes current locale)
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType When $content is not a valid Content object.
*
* @return string|null
*/
public function getTranslatedFieldDefinitionDescription(ValueObject $content, $fieldDefIdentifier, $forcedLanguage = null)
public function getTranslatedFieldDefinitionDescription(object $data, $fieldDefIdentifier, $forcedLanguage = null)
{
if ($contentType = $this->getContentType($content)) {
if ($contentType = $this->getContentType($this->resolveData($data))) {
return $this->translationHelper->getTranslatedFieldDefinitionProperty(
$contentType,
$fieldDefIdentifier,
Expand All @@ -233,11 +237,20 @@ public function getTranslatedFieldDefinitionDescription(ValueObject $content, $f
);
}

throw new InvalidArgumentType('$content', 'Content|ContentInfo', $content);
throw new InvalidArgumentType(
'$data',
sprintf('%s or %s or %s', Content::class, ContentInfo::class, ContentAwareInterface::class),
$data
);
}

public function hasField(Content $content, string $fieldDefIdentifier): bool
/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*/
public function hasField(object $data, string $fieldDefIdentifier): bool
{
$content = $this->getContent($data);

return $content->getContentType()->hasFieldDefinition($fieldDefIdentifier);
}

Expand All @@ -250,21 +263,21 @@ public function getFieldGroupName(string $identifier): ?string
* Checks if a given field is considered empty.
* This method accepts field as Objects or by identifiers.
*
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content $content
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Field|string $fieldDefIdentifier Field or Field Identifier to
* get the value from.
* @param string $forcedLanguage Locale we want the content name translation in (e.g. "fre-FR").
* Null by default (takes current locale).
*
* @return bool
*/
public function isFieldEmpty(Content $content, $fieldDefIdentifier, $forcedLanguage = null)
public function isFieldEmpty(object $data, $fieldDefIdentifier, $forcedLanguage = null)
{
if ($fieldDefIdentifier instanceof Field) {
$fieldDefIdentifier = $fieldDefIdentifier->fieldDefIdentifier;
}

return $this->fieldHelper->isFieldEmpty($content, $fieldDefIdentifier, $forcedLanguage);
return $this->fieldHelper->isFieldEmpty($this->getContent($data), $fieldDefIdentifier, $forcedLanguage);
}

/**
Expand All @@ -285,8 +298,12 @@ private function getContentType(ValueObject $content)
}
}

public function getFirstFilledImageFieldIdentifier(Content $content)
/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*/
public function getFirstFilledImageFieldIdentifier(object $data)
{
$content = $this->getContent($data);
foreach ($content->getFieldsByLanguage() as $field) {
$fieldTypeIdentifier = $content->getContentType()
->getFieldDefinition($field->fieldDefIdentifier)
Expand All @@ -305,6 +322,50 @@ public function getFirstFilledImageFieldIdentifier(Content $content)

return null;
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
*/
private function resolveData(object $data): ValueObject
{
if ($data instanceof Content || $data instanceof ContentInfo) {
return $data;
}

if ($data instanceof ContentAwareInterface) {
return $data->getContent();
}

throw new InvalidArgumentType(
'$content',
sprintf('%s or %s or %s', Content::class, ContentInfo::class, ContentAwareInterface::class),
$data,
);
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
*/
private function getContent(object $data): Content
{
if ($data instanceof Content) {
return $data;
}

if ($data instanceof ContentAwareInterface) {
return $data->getContent();
}

throw new InvalidArgumentType(
'$content',
sprintf('%s or %s', Content::class, ContentAwareInterface::class),
$data,
);
}
}

class_alias(ContentExtension::class, 'eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\ContentExtension');
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
namespace Ibexa\Core\MVC\Symfony\Templating\Twig\Extension;

use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface;
use Ibexa\Contracts\Core\Repository\Values\Content\Field;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
use Ibexa\Core\Base\Exceptions\InvalidArgumentType;
use Ibexa\Core\Helper\TranslationHelper;
use Ibexa\Core\MVC\Symfony\FieldType\View\ParameterProviderRegistryInterface;
use Ibexa\Core\MVC\Symfony\Templating\FieldBlockRendererInterface;
Expand Down Expand Up @@ -52,17 +54,22 @@ public function __construct(

public function getFunctions()
{
$renderFieldCallable = function (Environment $environment, Content $content, $fieldIdentifier, array $params = []) {
$renderFieldCallable = function (Environment $environment, $data, $fieldIdentifier, array $params = []) {
$this->fieldBlockRenderer->setTwig($environment);

return $this->renderField($content, $fieldIdentifier, $params);
return $this->renderField($this->getContent($data), $fieldIdentifier, $params);
};

$renderFieldDefinitionSettingsCallable = function (Environment $environment, FieldDefinition $fieldDefinition, array $params = []) {
$this->fieldBlockRenderer->setTwig($environment);
$renderFieldDefinitionSettingsCallable =
function (
Environment $environment,
FieldDefinition $fieldDefinition,
array $params = []
) {
$this->fieldBlockRenderer->setTwig($environment);

return $this->renderFieldDefinitionSettings($fieldDefinition, $params);
};
return $this->renderFieldDefinitionSettings($fieldDefinition, $params);
};

return [
new TwigFunction(
Expand Down Expand Up @@ -210,6 +217,27 @@ private function getFieldTypeIdentifier(Content $content, Field $field)

return $this->fieldTypeIdentifiers[$key];
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $content
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
*/
private function getContent(object $content): Content
{
if ($content instanceof Content) {
return $content;
}
if ($content instanceof ContentAwareInterface) {
return $content->getContent();
}

throw new InvalidArgumentType(
'$content',
sprintf('%s or %s', Content::class, ContentAwareInterface::class),
$content,
);
}
}

class_alias(FieldRenderingExtension::class, 'eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\FieldRenderingExtension');
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
namespace Ibexa\Core\MVC\Symfony\Templating\Twig\Extension;

use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface;
use Ibexa\Core\Base\Exceptions\InvalidArgumentType;
use Ibexa\Core\MVC\Symfony\Event\ResolveRenderOptionsEvent;
use Ibexa\Core\MVC\Symfony\Templating\RenderContentStrategy;
use Ibexa\Core\MVC\Symfony\Templating\RenderOptions;
Expand Down Expand Up @@ -58,14 +60,39 @@ public function getFunctions(): array
];
}

public function renderContent(Content $content, array $options = []): string
/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*/
public function renderContent(object $data, array $options = []): string
{
$renderOptions = new RenderOptions($options);
$event = $this->eventDispatcher->dispatch(
new ResolveRenderOptionsEvent($renderOptions)
);

return $this->renderContentStrategy->render($content, $event->getRenderOptions());
return $this->renderContentStrategy->render($this->getContent($data), $event->getRenderOptions());
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Content|\Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface $data
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
*/
private function getContent(object $data): Content
{
if ($data instanceof Content) {
return $data;
}

if ($data instanceof ContentAwareInterface) {
return $data->getContent();
}

throw new InvalidArgumentType(
'$content',
sprintf('%s or %s', Content::class, ContentAwareInterface::class),
$data,
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentAwareInterface;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
use Ibexa\Contracts\Core\Repository\Values\Content\Field;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
Expand Down Expand Up @@ -126,6 +127,20 @@ protected function getContent(string $contentTypeIdentifier, array $fieldsData,
return $content;
}

/**
* @param array<string, mixed> $fieldsData
* @param array<mixed> $namesData
*/
protected function getContentAwareObject(string $contentTypeIdentifier, array $fieldsData, array $namesData = []): ContentAwareInterface
{
$content = $this->getContent($contentTypeIdentifier, $fieldsData, $namesData);

$mock = $this->createMock(ContentAwareInterface::class);
$mock->method('getContent')->willReturn($content);

return $mock;
}

private function getConfigResolverMock()
{
$mock = $this->createMock(ConfigResolverInterface::class);
Expand Down
Loading
Loading