Link Templates
Link relation types and link templates
The links annotation in an entity definition specifies an array of link templates. The keys are link relation types, and the values are URL paths with placeholders to be replaced.
For example, the annotations for Drupal\media\Entity\Media include
* links = {
* "add-page" = "/media/add",
* "add-form" = "/media/add/{media_type}",
* "canonical" = "/media/{media}/edit",
* "collection" = "/admin/content/media",
* "delete-form" = "/media/{media}/delete",
* "delete-multiple-form" = "/media/delete",
* "edit-form" = "/media/{media}/edit",
* "revision" = "/media/{media}/revisions/{media_revision}/view",
* }Instead of defining link templates statically in the entity annotations, they can also be defined dynamically using setLinkTemplate(). See the section "Working with link templates" below.
In the link templates, the placeholders {media_type}, {media}, and {media_revision} are replaced with the media type (bundle), media ID, and revision ID. See the API doc EntityType::getLinkTemplates() for more information.
The link relation types canonical, delete-form, and many more are declared in core.link_relation_types.yml. A module can define additional link relation types. For example, workflows.link_relation_types.yml defines add-state-form and add-transition-form:
add-state-form:
uri: https://drupal.org/link-relations/add-state-form
description: A form where a state can be created.
add-transition-form:
uri: https://drupal.org/link-relations/add-transition-form
description: A form where a transition can be created.Using drush, you can generate a list of all the available link relation types:
drush php:eval 'print_r(array_keys(Drupal::service("plugin.manager.link_relation_type")->getDefinitions()))'Defining routes
Routes for these URL paths can be defined statically (in a .routing.yml file) or dynamically in a route provider. In either case, the route name should be "entity.$entity_type_id.$link_type", where $link_type is the link relation type with '-' replaced by '_'.
For example, media.routing.yml defines the route for one of the links shown in the first section:
entity.media.revision:
path: '/media/{media}/revisions/{media_revision}/view'
defaults:
_controller: '\Drupal\Core\Entity\Controller\EntityViewController::viewRevision'
_title_callback: '\Drupal\Core\Entity\Controller\EntityController::title'
options:
...The entity annotations (handlers.route_provider) can specify one or more route provider. Even though "route_provider" is singular, more than one is allowed. Looking at Drupal\media\Entity\Media again, the annotations include
* handlers = {
* ...
* "route_provider" = {
* "html" = "Drupal\media\Routing\MediaRouteProvider",
* },
* ...
* },The routes for three more of the links in the first section are defined in Drupal\media\Routing\MediaRouteProvider::getRoutes(). That class extends Drupal\Core\Entity\Routing\AdminHtmlRouteProvider.
For more information, see the Entity Routes section in the API pages for the Entity API.
Working with link templates
Drupal\Core\Entity\EntityType has methods
getLinkTemplate()getLinkTemplates()hasLinkTemplate()setLinkTemplate()
Example: config_translation_entity_type_alter() adds the config-translation-overview link to config entity types:
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
if ($entity_type->hasLinkTemplate('edit-form')) {
$entity_type->setLinkTemplate('config-translation-overview', $entity_type->getLinkTemplate('edit-form') . '/translate');
}Drupal\Core\Entity\EntityBase has methods
linkTemplates()hasLinkTemplate()toUrl()toLink()
The first method is used in EntityBase::toUrl(). Notice how the route name is derived from the link relation type:
// The links array might contain URI templates set in annotations.
$link_templates = $this->linkTemplates();
// ...
if (isset($link_templates[$rel])) {
$route_parameters = $this->urlRouteParameters($rel);
$route_name = "entity.{$this->entityTypeId}." . str_replace(['-', 'drupal:'], ['_', ''], $rel);
$uri = new Url($route_name, $route_parameters);
} The second method is used in Drupal\user\RoleListBuilder::getDefaultOperations() when adding the "Edit permissions" link to each row of /admin/people/roles:
if ($entity->hasLinkTemplate('edit-permissions-form')) {
$operations['permissions'] = [
'title' => t('Edit permissions'),
'weight' => 20,
'url' => $entity->toUrl('edit-permissions-form'),
];
}The last two methods accept a link relation type as an optional parameter (defaults to 'canonical'). The snippet above has an example of toUrl(). A common use of toLink() is to generate the edit link for a log message. For example, Drupal\taxonomy\TermForm::save() has
$edit_link = $term->toLink($this->t('Edit'), 'edit-form')->toString();Example: Link templates for the entity permissions form
The Node module adds a permissions form for the Article content type at /admin/structure/types/manage/article/permissions with these annotations in core/modules/node/src/Entity/NodeType.php:
* handlers = {
* ...
* "route_provider" = {
* "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
* },
* "list_builder" = "Drupal\node\NodeTypeListBuilder",
* },
* ...
* links = {
* "edit-form" = "/admin/structure/types/manage/{node_type}",
* "delete-form" = "/admin/structure/types/manage/{node_type}/delete",
* "entity-permissions-form" = "/admin/structure/types/manage/{node_type}/permissions",
* "collection" = "/admin/structure/types",
* },The real work is done in the User module, starting with core/modules/user/user.link_relation_types.yml:
# User extension relation types.
# See https://tools.ietf.org/html/rfc5988#section-4.2.
entity-permissions-form:
uri: https://drupal.org/link-relations/permissions
description: A form where bundle-related permissions can be managed.The route is defined in EntityPermissionsRouteProvider, which sets the form builder Drupal\user\Form\EntityPermissionsForm as the page controller.
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion
Still on Drupal 7? Security support for Drupal 7 ended on 5 January 2025. Please visit our Drupal 7 End of Life resources page to review all of your options.