RedirectSourceWidget.php 4.66 KB
Newer Older
1
2
3
4
<?php

namespace Drupal\redirect\Plugin\Field\FieldWidget;

5
use Drupal\Component\Utility\NestedArray;
6
7
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Field\FieldItemListInterface;
8
use Drupal\Core\Field\WidgetBase;
9
use Drupal\Core\Url;
Berdir's avatar
Berdir committed
10
use Drupal\Core\Form\FormStateInterface;
11
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
Berdir's avatar
Berdir committed
12
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
13
14
15
16
17
18
19
20

/**
 * Plugin implementation of the 'link' widget for the redirect module.
 *
 * Note that this field is meant only for the source field of the redirect
 * entity as it drops validation for non existing paths.
 *
 * @FieldWidget(
21
22
 *   id = "redirect_source",
 *   label = @Translation("Redirect source"),
23
24
25
26
27
28
29
30
31
 *   field_types = {
 *     "link"
 *   },
 *   settings = {
 *     "placeholder_url" = "",
 *     "placeholder_title" = ""
 *   }
 * )
 */
32
class RedirectSourceWidget extends WidgetBase {
33

34
35
36
  /**
   * {@inheritdoc}
   */
Berdir's avatar
Berdir committed
37
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
38
39
40
41
    $default_url_value = $items[$delta]->path;
    if ($items[$delta]->query) {
      $default_url_value .= '?' . http_build_query($items[$delta]->query);
    }
42
    $element['path'] = [
43
      '#type' => 'textfield',
44
      '#title' => $this->t('Path'),
45
46
47
48
      '#placeholder' => $this->getSetting('placeholder_url'),
      '#default_value' => $default_url_value,
      '#maxlength' => 2048,
      '#required' => $element['#required'],
49
50
51
      '#field_prefix' => Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(),
      '#attributes' => ['data-disable-refocus' => 'true'],
    ];
52
53
54

    // If creating new URL add checks.
    if ($items->getEntity()->isNew()) {
55
      $element['status_box'] = [
56
57
        '#prefix' => '<div id="redirect-link-status">',
        '#suffix' => '</div>',
58
      ];
59

60
      $source_path = $form_state->getValue(['redirect_source', 0, 'path']);
61
62
      if ($source_path) {
        $source_path = trim($source_path);
63
64
65
66
67

        // Warning about creating a redirect from a valid path.
        // @todo - Hmm... exception driven logic. Find a better way how to
        //   determine if we have a valid path.
        try {
68
          \Drupal::service('router')->match('/' . $form_state->getValue(['redirect_source', 0, 'path']));
69
          $element['status_box'][]['#markup'] = '<div class="messages messages--warning">' . $this->t('The source path %path is likely a valid path. It is preferred to <a href="@url-alias">create URL aliases</a> for existing paths rather than redirects.',
70
              ['%path' => $source_path, '@url-alias' => Url::fromRoute('entity.path_alias.add_form')->toString()]) . '</div>';
71
72
73
74
        }
        catch (ResourceNotFoundException $e) {
          // Do nothing, expected behaviour.
        }
75
76
77
        catch (AccessDeniedHttpException $e) {
          // @todo Source lookup results in an access denied, deny access?
        }
78
79

        // Warning about the path being already redirected.
80
        $parsed_url = UrlHelper::parse($source_path);
81
82
        $path = isset($parsed_url['path']) ? $parsed_url['path'] : NULL;
        if (!empty($path)) {
83
84
85
          /** @var \Drupal\redirect\RedirectRepository $repository */
          $repository = \Drupal::service('redirect.repository');
          $redirects = $repository->findBySourcePath($path);
86
87
          if (!empty($redirects)) {
            $redirect = array_shift($redirects);
88
            $element['status_box'][]['#markup'] = '<div class="messages messages--warning">' . $this->t('The base source path %source is already being redirected. Do you want to <a href="@edit-page">edit the existing redirect</a>?', ['%source' => $source_path, '@edit-page' => $redirect->toUrl('edit-form')->toString()]) . '</div>';
89
90
91
92
          }
        }
      }

93
      $element['path']['#ajax'] = [
94
95
        'callback' => 'redirect_source_link_get_status_messages',
        'wrapper' => 'redirect-link-status',
96
      ];
97
    }
98
99
100
101
102
103
104

    return $element;
  }

  /**
   * {@inheritdoc}
   */
Berdir's avatar
Berdir committed
105
  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
106
107
108
109
    $values = parent::massageFormValues($values, $form, $form_state);
    // It is likely that the url provided for this field is not existing and
    // so the logic in the parent method did not set any defaults. Just run
    // through all url values and add defaults.
110
    foreach ($values as &$value) {
111
      if (!empty($value['path'])) {
blueminds's avatar
blueminds committed
112
        // In case we have query process the url.
113
114
115
116
        if (strpos($value['path'], '?') !== FALSE) {
          $url = UrlHelper::parse($value['path']);
          $value['path'] = $url['path'];
          $value['query'] = $url['query'];
blueminds's avatar
blueminds committed
117
        }
118
119
120
121
122
      }
    }
    return $values;
  }
}