From 5651ec3213133c1466881b1a0f98cca11571f4ff Mon Sep 17 00:00:00 2001 From: Maks Oleksyuk Date: Sat, 7 Mar 2026 14:56:59 +0200 Subject: [PATCH 1/3] feat: add `renderAsLinkToEntity` option to TextField --- src/Field/TextField.php | 9 +++++++++ templates/crud/field/text.html.twig | 8 +++++++- tests/Unit/Field/TextFieldTest.php | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Field/TextField.php b/src/Field/TextField.php index c625fc6e8b..2a3cde2c62 100644 --- a/src/Field/TextField.php +++ b/src/Field/TextField.php @@ -15,6 +15,7 @@ final class TextField implements FieldInterface public const OPTION_MAX_LENGTH = 'maxLength'; public const OPTION_RENDER_AS_HTML = 'renderAsHtml'; + public const OPTION_RENDER_AS_LINK_TO_ENTITY = 'renderAsLinkToEntity'; public const OPTION_STRIP_TAGS = 'stripTags'; public static function new(string $propertyName, TranslatableInterface|string|bool|null $label = null): self @@ -28,6 +29,7 @@ public static function new(string $propertyName, TranslatableInterface|string|bo ->setDefaultColumns('col-md-6 col-xxl-5') ->setCustomOption(self::OPTION_MAX_LENGTH, null) ->setCustomOption(self::OPTION_RENDER_AS_HTML, false) + ->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_ENTITY, false) ->setCustomOption(self::OPTION_STRIP_TAGS, false); } @@ -53,6 +55,13 @@ public function renderAsHtml(bool $asHtml = true): self return $this; } + public function renderAsLinkToEntity(bool $asLink = true): self + { + $this->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_ENTITY, $asLink); + + return $this; + } + public function stripTags(bool $stripTags = true): self { $this->setCustomOption(self::OPTION_STRIP_TAGS, $stripTags); diff --git a/templates/crud/field/text.html.twig b/templates/crud/field/text.html.twig index a3b3e9a365..cfdafddd86 100644 --- a/templates/crud/field/text.html.twig +++ b/templates/crud/field/text.html.twig @@ -1,7 +1,13 @@ {# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} -{% if ea().crud.currentAction == 'detail' %} +{% if field.customOptions.get('renderAsLinkToEntity') and ea().crud.currentAction == 'index' %} + {% set url = ea_url() + .setAction('detail') + .setEntityId(entity.primaryKeyValue) + %} + {{ field.formattedValue|raw }} +{% elseif ea().crud.currentAction == 'detail' %} {{ field.formattedValue|raw|nl2br }} {% else %} {{ field.formattedValue|raw }} diff --git a/tests/Unit/Field/TextFieldTest.php b/tests/Unit/Field/TextFieldTest.php index bef7899692..1b8222ef17 100644 --- a/tests/Unit/Field/TextFieldTest.php +++ b/tests/Unit/Field/TextFieldTest.php @@ -136,6 +136,23 @@ public function testHtmlEntitiesAreEscapedByDefault(): void self::assertStringContainsString('<script>', $fieldDto->getFormattedValue()); } + public function testRenderAsLinkToEntity(): void + { + $field = TextField::new('foo'); + $field->renderAsLinkToEntity(); + $fieldDto = $this->configure($field); + + self::assertTrue($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_ENTITY)); + } + + public function testRenderAsLinkToEntityDefaultIsFalse(): void + { + $field = TextField::new('foo'); + $fieldDto = $this->configure($field); + + self::assertFalse($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_ENTITY)); + } + public function testBackedEnumValue(): void { // create a backed enum for testing From cfbeaf832325c1aee45120eede61eaf1bd427c92 Mon Sep 17 00:00:00 2001 From: Maks Oleksyuk Date: Sat, 7 Mar 2026 15:06:39 +0200 Subject: [PATCH 2/3] docs: add documentation for `renderAsLinkToEntity` in TextField --- doc/fields/TextField.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/fields/TextField.rst b/doc/fields/TextField.rst index 1c01501e98..f297cc428c 100644 --- a/doc/fields/TextField.rst +++ b/doc/fields/TextField.rst @@ -67,6 +67,20 @@ pages (``new`` and ``edit``) contents are never truncated in length. This option is ignored when also using the ``renderAsHtml()`` option, to avoid truncating contents in the middle of an opened HTML tag. +``renderAsLinkToEntity`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, text contents are displayed as plain text. If you want the field +value to be rendered as a link to the entity's detail page on the ``index`` +page, use this option:: + + yield TextField::new('...')->renderAsLinkToEntity(); + +This is useful when you want to let users click on a text value (e.g. a name +or a title) to navigate directly to the entity's detail page. + +This option only has effect on the ``index`` page. + ``stripTags`` ~~~~~~~~~~~~~ From 7fa7006d7f1c5ba7bb119329369728a45daaa852 Mon Sep 17 00:00:00 2001 From: Maks Oleksyuk Date: Thu, 26 Mar 2026 17:08:14 +0200 Subject: [PATCH 3/3] refactor: rename `renderAsLinkToEntity` to `renderAsLinkToDetailAction` in TextField --- doc/fields/TextField.rst | 6 +++--- src/Field/TextField.php | 8 ++++---- templates/crud/field/text.html.twig | 2 +- tests/Unit/Field/TextFieldTest.php | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/fields/TextField.rst b/doc/fields/TextField.rst index f297cc428c..b7aaa05e4f 100644 --- a/doc/fields/TextField.rst +++ b/doc/fields/TextField.rst @@ -67,14 +67,14 @@ pages (``new`` and ``edit``) contents are never truncated in length. This option is ignored when also using the ``renderAsHtml()`` option, to avoid truncating contents in the middle of an opened HTML tag. -``renderAsLinkToEntity`` -~~~~~~~~~~~~~~~~~~~~~~~~ +``renderAsLinkToDetailAction`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, text contents are displayed as plain text. If you want the field value to be rendered as a link to the entity's detail page on the ``index`` page, use this option:: - yield TextField::new('...')->renderAsLinkToEntity(); + yield TextField::new('...')->renderAsLinkToDetailAction(); This is useful when you want to let users click on a text value (e.g. a name or a title) to navigate directly to the entity's detail page. diff --git a/src/Field/TextField.php b/src/Field/TextField.php index 2a3cde2c62..06c89a9d14 100644 --- a/src/Field/TextField.php +++ b/src/Field/TextField.php @@ -15,7 +15,7 @@ final class TextField implements FieldInterface public const OPTION_MAX_LENGTH = 'maxLength'; public const OPTION_RENDER_AS_HTML = 'renderAsHtml'; - public const OPTION_RENDER_AS_LINK_TO_ENTITY = 'renderAsLinkToEntity'; + public const OPTION_RENDER_AS_LINK_TO_DETAIL_ACTION = 'renderAsLinkToDetailAction'; public const OPTION_STRIP_TAGS = 'stripTags'; public static function new(string $propertyName, TranslatableInterface|string|bool|null $label = null): self @@ -29,7 +29,7 @@ public static function new(string $propertyName, TranslatableInterface|string|bo ->setDefaultColumns('col-md-6 col-xxl-5') ->setCustomOption(self::OPTION_MAX_LENGTH, null) ->setCustomOption(self::OPTION_RENDER_AS_HTML, false) - ->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_ENTITY, false) + ->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_DETAIL_ACTION, false) ->setCustomOption(self::OPTION_STRIP_TAGS, false); } @@ -55,9 +55,9 @@ public function renderAsHtml(bool $asHtml = true): self return $this; } - public function renderAsLinkToEntity(bool $asLink = true): self + public function renderAsLinkToDetailAction(bool $asLink = true): self { - $this->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_ENTITY, $asLink); + $this->setCustomOption(self::OPTION_RENDER_AS_LINK_TO_DETAIL_ACTION, $asLink); return $this; } diff --git a/templates/crud/field/text.html.twig b/templates/crud/field/text.html.twig index cfdafddd86..39589aea20 100644 --- a/templates/crud/field/text.html.twig +++ b/templates/crud/field/text.html.twig @@ -1,7 +1,7 @@ {# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #} {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} -{% if field.customOptions.get('renderAsLinkToEntity') and ea().crud.currentAction == 'index' %} +{% if field.customOptions.get('renderAsLinkToDetailAction') and ea().crud.currentAction == 'index' %} {% set url = ea_url() .setAction('detail') .setEntityId(entity.primaryKeyValue) diff --git a/tests/Unit/Field/TextFieldTest.php b/tests/Unit/Field/TextFieldTest.php index 1b8222ef17..efc5e6944d 100644 --- a/tests/Unit/Field/TextFieldTest.php +++ b/tests/Unit/Field/TextFieldTest.php @@ -136,21 +136,21 @@ public function testHtmlEntitiesAreEscapedByDefault(): void self::assertStringContainsString('<script>', $fieldDto->getFormattedValue()); } - public function testRenderAsLinkToEntity(): void + public function testRenderAsLinkToDetailAction(): void { $field = TextField::new('foo'); - $field->renderAsLinkToEntity(); + $field->renderAsLinkToDetailAction(); $fieldDto = $this->configure($field); - self::assertTrue($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_ENTITY)); + self::assertTrue($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_DETAIL_ACTION)); } - public function testRenderAsLinkToEntityDefaultIsFalse(): void + public function testRenderAsLinkToDetailActionDefaultIsFalse(): void { $field = TextField::new('foo'); $fieldDto = $this->configure($field); - self::assertFalse($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_ENTITY)); + self::assertFalse($fieldDto->getCustomOption(TextField::OPTION_RENDER_AS_LINK_TO_DETAIL_ACTION)); } public function testBackedEnumValue(): void