Link.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <?php
  2. namespace Drupal\Core\Render\Element;
  3. use Drupal\Component\Utility\NestedArray;
  4. use Drupal\Component\Utility\Html as HtmlUtility;
  5. use Drupal\Core\Render\BubbleableMetadata;
  6. use Drupal\Core\Url as CoreUrl;
  7. /**
  8. * Provides a link render element.
  9. *
  10. * Properties:
  11. * - #title: The link text.
  12. * - #url: \Drupal\Core\Url object containing URL information pointing to a
  13. * internal or external link. See \Drupal\Core\Utility\LinkGeneratorInterface.
  14. *
  15. * Usage example:
  16. * @code
  17. * $build['examples_link'] = [
  18. * '#title' => $this->t('Examples'),
  19. * '#type' => 'link',
  20. * '#url' => \Drupal\Core\Url::fromRoute('examples.description')
  21. * ];
  22. * @endcode
  23. *
  24. * @RenderElement("link")
  25. */
  26. class Link extends RenderElement {
  27. /**
  28. * {@inheritdoc}
  29. */
  30. public function getInfo() {
  31. $class = get_class($this);
  32. return [
  33. '#pre_render' => [
  34. [$class, 'preRenderLink'],
  35. ],
  36. ];
  37. }
  38. /**
  39. * Pre-render callback: Renders a link into #markup.
  40. *
  41. * Doing so during pre_render gives modules a chance to alter the link parts.
  42. *
  43. * @param array $element
  44. * A structured array whose keys form the arguments to
  45. * \Drupal\Core\Utility\LinkGeneratorInterface::generate():
  46. * - #title: The link text.
  47. * - #url: The URL info either pointing to a route or a non routed path.
  48. * - #options: (optional) An array of options to pass to the link generator.
  49. *
  50. * @return array
  51. * The passed-in element containing a rendered link in '#markup'.
  52. */
  53. public static function preRenderLink($element) {
  54. // By default, link options to pass to the link generator are normally set
  55. // in #options.
  56. $element += ['#options' => []];
  57. // However, within the scope of renderable elements, #attributes is a valid
  58. // way to specify attributes, too. Take them into account, but do not override
  59. // attributes from #options.
  60. if (isset($element['#attributes'])) {
  61. $element['#options'] += ['attributes' => []];
  62. $element['#options']['attributes'] += $element['#attributes'];
  63. }
  64. // This #pre_render callback can be invoked from inside or outside of a Form
  65. // API context, and depending on that, a HTML ID may be already set in
  66. // different locations. #options should have precedence over Form API's #id.
  67. // #attributes have been taken over into #options above already.
  68. if (isset($element['#options']['attributes']['id'])) {
  69. $element['#id'] = $element['#options']['attributes']['id'];
  70. }
  71. elseif (isset($element['#id'])) {
  72. $element['#options']['attributes']['id'] = $element['#id'];
  73. }
  74. // Conditionally invoke self::preRenderAjaxForm(), if #ajax is set.
  75. if (isset($element['#ajax']) && !isset($element['#ajax_processed'])) {
  76. // If no HTML ID was found above, automatically create one.
  77. if (!isset($element['#id'])) {
  78. $element['#id'] = $element['#options']['attributes']['id'] = HtmlUtility::getUniqueId('ajax-link');
  79. }
  80. $element = static::preRenderAjaxForm($element);
  81. }
  82. if (!empty($element['#url']) && $element['#url'] instanceof CoreUrl) {
  83. $options = NestedArray::mergeDeep($element['#url']->getOptions(), $element['#options']);
  84. /** @var \Drupal\Core\Utility\LinkGenerator $link_generator */
  85. $link_generator = \Drupal::service('link_generator');
  86. $generated_link = $link_generator->generate($element['#title'], $element['#url']->setOptions($options));
  87. $element['#markup'] = $generated_link;
  88. $generated_link->merge(BubbleableMetadata::createFromRenderArray($element))
  89. ->applyTo($element);
  90. }
  91. return $element;
  92. }
  93. }