Version 1
[yaffs-website] / web / core / modules / link / src / Plugin / Field / FieldFormatter / LinkFormatter.php
1 <?php
2
3 namespace Drupal\link\Plugin\Field\FieldFormatter;
4
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Core\Field\FieldDefinitionInterface;
7 use Drupal\Core\Field\FieldItemListInterface;
8 use Drupal\Core\Field\FormatterBase;
9 use Drupal\Core\Form\FormStateInterface;
10 use Drupal\Core\Path\PathValidatorInterface;
11 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
12 use Drupal\Core\Url;
13 use Drupal\link\LinkItemInterface;
14 use Symfony\Component\DependencyInjection\ContainerInterface;
15
16 /**
17  * Plugin implementation of the 'link' formatter.
18  *
19  * @FieldFormatter(
20  *   id = "link",
21  *   label = @Translation("Link"),
22  *   field_types = {
23  *     "link"
24  *   }
25  * )
26  */
27 class LinkFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
28
29   /**
30    * The path validator service.
31    *
32    * @var \Drupal\Core\Path\PathValidatorInterface
33    */
34   protected $pathValidator;
35
36   /**
37    * {@inheritdoc}
38    */
39   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
40     return new static(
41       $plugin_id,
42       $plugin_definition,
43       $configuration['field_definition'],
44       $configuration['settings'],
45       $configuration['label'],
46       $configuration['view_mode'],
47       $configuration['third_party_settings'],
48       $container->get('path.validator')
49     );
50   }
51
52   /**
53    * Constructs a new LinkFormatter.
54    *
55    * @param string $plugin_id
56    *   The plugin_id for the formatter.
57    * @param mixed $plugin_definition
58    *   The plugin implementation definition.
59    * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
60    *   The definition of the field to which the formatter is associated.
61    * @param array $settings
62    *   The formatter settings.
63    * @param string $label
64    *   The formatter label display setting.
65    * @param string $view_mode
66    *   The view mode.
67    * @param array $third_party_settings
68    *   Third party settings.
69    * @param \Drupal\Core\Path\PathValidatorInterface $path_validator
70    *   The path validator service.
71    */
72   public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, PathValidatorInterface $path_validator) {
73     parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
74     $this->pathValidator = $path_validator;
75   }
76
77   /**
78    * {@inheritdoc}
79    */
80   public static function defaultSettings() {
81     return [
82       'trim_length' => '80',
83       'url_only' => '',
84       'url_plain' => '',
85       'rel' => '',
86       'target' => '',
87     ] + parent::defaultSettings();
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function settingsForm(array $form, FormStateInterface $form_state) {
94     $elements = parent::settingsForm($form, $form_state);
95
96     $elements['trim_length'] = [
97       '#type' => 'number',
98       '#title' => t('Trim link text length'),
99       '#field_suffix' => t('characters'),
100       '#default_value' => $this->getSetting('trim_length'),
101       '#min' => 1,
102       '#description' => t('Leave blank to allow unlimited link text lengths.'),
103     ];
104     $elements['url_only'] = [
105       '#type' => 'checkbox',
106       '#title' => t('URL only'),
107       '#default_value' => $this->getSetting('url_only'),
108       '#access' => $this->getPluginId() == 'link',
109     ];
110     $elements['url_plain'] = [
111       '#type' => 'checkbox',
112       '#title' => t('Show URL as plain text'),
113       '#default_value' => $this->getSetting('url_plain'),
114       '#access' => $this->getPluginId() == 'link',
115       '#states' => [
116         'visible' => [
117           ':input[name*="url_only"]' => ['checked' => TRUE],
118         ],
119       ],
120     ];
121     $elements['rel'] = [
122       '#type' => 'checkbox',
123       '#title' => t('Add rel="nofollow" to links'),
124       '#return_value' => 'nofollow',
125       '#default_value' => $this->getSetting('rel'),
126     ];
127     $elements['target'] = [
128       '#type' => 'checkbox',
129       '#title' => t('Open link in new window'),
130       '#return_value' => '_blank',
131       '#default_value' => $this->getSetting('target'),
132     ];
133
134     return $elements;
135   }
136
137   /**
138    * {@inheritdoc}
139    */
140   public function settingsSummary() {
141     $summary = [];
142
143     $settings = $this->getSettings();
144
145     if (!empty($settings['trim_length'])) {
146       $summary[] = t('Link text trimmed to @limit characters', ['@limit' => $settings['trim_length']]);
147     }
148     else {
149       $summary[] = t('Link text not trimmed');
150     }
151     if ($this->getPluginId() == 'link' && !empty($settings['url_only'])) {
152       if (!empty($settings['url_plain'])) {
153         $summary[] = t('Show URL only as plain-text');
154       }
155       else {
156         $summary[] = t('Show URL only');
157       }
158     }
159     if (!empty($settings['rel'])) {
160       $summary[] = t('Add rel="@rel"', ['@rel' => $settings['rel']]);
161     }
162     if (!empty($settings['target'])) {
163       $summary[] = t('Open link in new window');
164     }
165
166     return $summary;
167   }
168
169   /**
170    * {@inheritdoc}
171    */
172   public function viewElements(FieldItemListInterface $items, $langcode) {
173     $element = [];
174     $entity = $items->getEntity();
175     $settings = $this->getSettings();
176
177     foreach ($items as $delta => $item) {
178       // By default use the full URL as the link text.
179       $url = $this->buildUrl($item);
180       $link_title = $url->toString();
181
182       // If the title field value is available, use it for the link text.
183       if (empty($settings['url_only']) && !empty($item->title)) {
184         // Unsanitized token replacement here because the entire link title
185         // gets auto-escaped during link generation in
186         // \Drupal\Core\Utility\LinkGenerator::generate().
187         $link_title = \Drupal::token()->replace($item->title, [$entity->getEntityTypeId() => $entity], ['clear' => TRUE]);
188       }
189
190       // Trim the link text to the desired length.
191       if (!empty($settings['trim_length'])) {
192         $link_title = Unicode::truncate($link_title, $settings['trim_length'], FALSE, TRUE);
193       }
194
195       if (!empty($settings['url_only']) && !empty($settings['url_plain'])) {
196         $element[$delta] = [
197           '#plain_text' => $link_title,
198         ];
199
200         if (!empty($item->_attributes)) {
201           // Piggyback on the metadata attributes, which will be placed in the
202           // field template wrapper, and set the URL value in a content
203           // attribute.
204           // @todo Does RDF need a URL rather than an internal URI here?
205           // @see \Drupal\Tests\rdf\Kernel\Field\LinkFieldRdfaTest.
206           $content = str_replace('internal:/', '', $item->uri);
207           $item->_attributes += ['content' => $content];
208         }
209       }
210       else {
211         $element[$delta] = [
212           '#type' => 'link',
213           '#title' => $link_title,
214           '#options' => $url->getOptions(),
215         ];
216         $element[$delta]['#url'] = $url;
217
218         if (!empty($item->_attributes)) {
219           $element[$delta]['#options'] += ['attributes' => []];
220           $element[$delta]['#options']['attributes'] += $item->_attributes;
221           // Unset field item attributes since they have been included in the
222           // formatter output and should not be rendered in the field template.
223           unset($item->_attributes);
224         }
225       }
226     }
227
228     return $element;
229   }
230
231   /**
232    * Builds the \Drupal\Core\Url object for a link field item.
233    *
234    * @param \Drupal\link\LinkItemInterface $item
235    *   The link field item being rendered.
236    *
237    * @return \Drupal\Core\Url
238    *   A Url object.
239    */
240   protected function buildUrl(LinkItemInterface $item) {
241     $url = $item->getUrl() ?: Url::fromRoute('<none>');
242
243     $settings = $this->getSettings();
244     $options = $item->options;
245     $options += $url->getOptions();
246
247     // Add optional 'rel' attribute to link options.
248     if (!empty($settings['rel'])) {
249       $options['attributes']['rel'] = $settings['rel'];
250     }
251     // Add optional 'target' attribute to link options.
252     if (!empty($settings['target'])) {
253       $options['attributes']['target'] = $settings['target'];
254     }
255     $url->setOptions($options);
256
257     return $url;
258   }
259
260 }