diff --git a/docs/cheat-sheet.md b/docs/cheat-sheet.md index dd53de4..8c4ca30 100644 --- a/docs/cheat-sheet.md +++ b/docs/cheat-sheet.md @@ -311,6 +311,28 @@ It is also possible to extract file URL directly from an entity. {{ media|file_url }} ``` +## Entity URL +Gets the URL object for the entity. +See \Drupal\Core\Entity\EntityInterface::toUrl() +```twig +{# Creates canonical URL for the node. #} +{{ node|entity_url }} + +{# Creates URL for the node edit form. #} +{{ node|entity_url('edit-form') }} +``` + +## Entity Link +Generates the HTML for a link to this entity. +See \Drupal\Core\Entity\EntityInterface::toLink() +```twig +{# Creates a link to the node using the node's label. #} +{{ node|entity_link }} + +{# Creates link to node comment form. #} +{{ node|entity_link('Add new comment'|t, 'canonical', {fragment: 'comment-form'}) }} +``` + ## Entity translation That is typically needed when printing data from referenced entities. ```twig diff --git a/src/TwigTweakExtension.php b/src/TwigTweakExtension.php index 4d7ad01..d62a343 100644 --- a/src/TwigTweakExtension.php +++ b/src/TwigTweakExtension.php @@ -112,6 +112,8 @@ class TwigTweakExtension extends AbstractExtension { new TwigFilter('children', [self::class, 'childrenFilter']), new TwigFilter('file_uri', [self::class, 'fileUriFilter']), new TwigFilter('file_url', [self::class, 'fileUrlFilter']), + new TwigFilter('entity_url', [self::class, 'entityUrl']), + new TwigFilter('entity_link', [self::class, 'entityLink']), new TwigFilter('translation', [self::class, 'entityTranslation']), new TwigFilter('cache_metadata', [self::class, 'CacheMetadata']), ]; @@ -624,6 +626,30 @@ class TwigTweakExtension extends AbstractExtension { return \Drupal::service('twig_tweak.url_extractor')->extractUrl($input, $relative); } + /** + * Gets the URL object for the entity. + * + * @todo Remove this once Drupal allows `toUrl` method in the sandbox policy. + * + * @see https://www.drupal.org/node/2907810 + * @see \Drupal\Core\Entity\EntityInterface::toUrl() + */ + public static function entityUrl(EntityInterface $entity, string $rel = 'canonical', array $options = []): Url { + return $entity->toUrl($rel, $options); + } + + /** + * Gets the URL object for the entity. + * + * @todo Remove this once Drupal allows `toLink` method in the sandbox policy. + * + * @see https://www.drupal.org/node/2907810 + * @see \Drupal\Core\Entity\EntityInterface::toLink() + */ + public static function entityLink(EntityInterface $entity, ?string $text = NULL, string $rel = 'canonical', array $options = []): Link { + return $entity->toLink($text, $rel, $options); + } + /** * Returns the translation for the given entity. * diff --git a/tests/src/Functional/TwigTweakTest.php b/tests/src/Functional/TwigTweakTest.php index b9964d8..7d96d80 100644 --- a/tests/src/Functional/TwigTweakTest.php +++ b/tests/src/Functional/TwigTweakTest.php @@ -390,6 +390,30 @@ final class TwigTweakTest extends BrowserTestBase { $xpath = '//div[@class = "tt-file-url-from-media-field" and contains(text(), "/files/image-1.png")]'; $this->assertXpath($xpath); + // -- Entity URL (canonical). + $xpath = '//div[@class = "tt-entity-url" and contains(text(), "/node/1#test") and not(contains(text(), "http"))]'; + $this->assertXpath($xpath); + + // -- Entity URL (absolute). + $xpath = '//div[@class = "tt-entity-url-absolute" and contains(text(), "/node/1") and contains(text(), "http")]'; + $this->assertXpath($xpath); + + // -- Entity URL (edit form). + $xpath = '//div[@class = "tt-entity-url-edit-form" and contains(text(), "/node/1/edit")]'; + $this->assertXpath($xpath); + + // -- Entity Link (canonical). + $xpath = '//div[@class = "tt-entity-link"]/a[text() = "Alpha" and contains(@href, "/node/1") and not(contains(@href, "http"))]'; + $this->assertXpath($xpath); + + // -- Entity Link (absolute). + $xpath = '//div[@class = "tt-entity-link-absolute"]/a[text() = "Example" and contains(@href, "/node/1") and contains(@href, "http")]'; + $this->assertXpath($xpath); + + // -- Entity Link (edit form). + $xpath = '//div[@class = "tt-entity-link-edit-form"]/a[text() = "Edit" and contains(@href, "/node/1/edit")]'; + $this->assertXpath($xpath); + // -- Entity translation. // This is just a smoke test because the node is not translatable. $xpath = '//div[@class = "tt-translation" and contains(text(), "Alpha")]'; diff --git a/tests/twig_tweak_test/templates/twig-tweak-test.html.twig b/tests/twig_tweak_test/templates/twig-tweak-test.html.twig index 3c3c2dd..e6dd6c3 100644 --- a/tests/twig_tweak_test/templates/twig-tweak-test.html.twig +++ b/tests/twig_tweak_test/templates/twig-tweak-test.html.twig @@ -99,6 +99,12 @@
{{ node.field_image|file_url }}
{{ node.field_image[0]|file_url }}
{{ node.field_media|file_url }}
+
{{ node|entity_url(options={fragment: 'test'}) }}
+
{{ node|entity_url(options={absolute: true}) }}
+
{{ node|entity_url('edit-form') }}
+ + +
{{ (node|translation).title.value }}
{{ foo('bar') }}
{{ 'foo'|bar }}