path.module 8.14 KB
Newer Older
Steven Wittens's avatar
Steven Wittens committed
1 2 3 4 5 6 7
<?php

/**
 * @file
 * Enables users to rename URLs.
 */

8
use Drupal\Core\Entity\EntityTypeInterface;
9
use Drupal\Core\Language\Language;
10
use Drupal\Core\Entity\EntityInterface;
11
use Drupal\Core\Entity\ContentEntityInterface;
12
use Drupal\Core\Field\FieldDefinition;
13

Steven Wittens's avatar
Steven Wittens committed
14
/**
15
 * Implements hook_help().
Steven Wittens's avatar
Steven Wittens committed
16
 */
17 18
function path_help($path, $arg) {
  switch ($path) {
Steven Wittens's avatar
Steven Wittens committed
19
    case 'admin/help#path':
20 21
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
22
      $output .= '<p>' . t('The Path module allows you to specify an alias, or custom URL, for any existing internal system path. Aliases should not be confused with URL redirects, which allow you to forward a changed or inactive URL to a new URL. In addition to making URLs more readable, aliases also help search engines index content more effectively. Multiple aliases may be used for a single internal system path. To automate the aliasing of paths, you can install the contributed module <a href="@pathauto">Pathauto</a>. For more information, see the online handbook entry for the <a href="@path">Path module</a>.', array('@path' => 'http://drupal.org/documentation/modules/path', '@pathauto' => 'http://drupal.org/project/pathauto')) . '</p>';
23 24 25
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Creating aliases') . '</dt>';
26
      $output .= '<dd>' . t('Users with sufficient <a href="@permissions">permissions</a> can create aliases under the <em>URL path settings</em> section when they create or edit content. Some examples of aliases are: ', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-path'))));
27 28 29 30
      $output .= '<ul><li>' . t('<em>member/jane-smith</em> aliased to internal path <em>user/123</em>') . '</li>';
      $output .= '<li>' . t('<em>about-us/team</em> aliased to internal path <em>node/456</em>') . '</li>';
      $output .= '</ul></dd>';
      $output .= '<dt>' . t('Managing aliases') . '</dt>';
31
      $output .= '<dd>' . t('The Path module provides a way to search and view a <a href="@aliases">list of all aliases</a> that are in use on your website. Aliases can be added, edited and deleted through this list.', array('@aliases' => url('admin/config/search/path'))) . '</dd>';
32
      $output .= '</dl>';
Steven Wittens's avatar
Steven Wittens committed
33
      return $output;
34

35
    case 'admin/config/search/path':
36
      return '<p>' . t("An alias defines a different name for an existing URL path - for example, the alias 'about' for the URL path 'node/1'. A URL path can have multiple aliases.") . '</p>';
37

38
    case 'admin/config/search/path/add':
39
      return '<p>' . t('Enter the path you wish to create the alias for, followed by the name of the new alias.') . '</p>';
Steven Wittens's avatar
Steven Wittens committed
40 41 42
  }
}

43
/**
44
 * Implements hook_permission().
45 46 47 48 49 50 51
 */
function path_permission() {
  return array(
    'administer url aliases' => array(
      'title' => t('Administer URL aliases'),
    ),
    'create url aliases' => array(
52
      'title' => t('Create and edit URL aliases'),
53 54 55 56
    ),
  );
}

Steven Wittens's avatar
Steven Wittens committed
57
/**
58 59 60
 * Implements hook_form_BASE_FORM_ID_alter() for node_form().
 *
 * @see path_form_element_validate()
Steven Wittens's avatar
Steven Wittens committed
61
 */
62
function path_form_node_form_alter(&$form, $form_state) {
63
  $node = $form_state['controller']->getEntity();
64
  $path = array();
65 66
  if (!$node->isNew()) {
    $conditions = array('source' => 'node/' . $node->id());
67 68
    if ($node->language()->id != Language::LANGCODE_NOT_SPECIFIED) {
      $conditions['langcode'] = $node->language()->id;
69
    }
70
    $path = \Drupal::service('path.alias_storage')->load($conditions);
71 72
    if ($path === FALSE) {
      $path = array();
73 74
    }
  }
75 76
  $path += array(
    'pid' => NULL,
77
    'source' => $node->id() ? 'node/' . $node->id() : NULL,
78
    'alias' => '',
79
    'langcode' => $node->language()->id,
80 81
  );

82
  $account = \Drupal::currentUser();
83
  $form['path'] = array(
84
    '#type' => 'details',
85
    '#title' => t('URL path settings'),
86
    '#open' => !empty($path['alias']),
87
    '#group' => 'advanced',
88 89 90
    '#attributes' => array(
      'class' => array('path-form'),
    ),
91
    '#attached' => array(
92
      'library' => array('path/drupal.path'),
93
    ),
94
    '#access' => $account->hasPermission('create url aliases') || $account->hasPermission('administer url aliases'),
95 96 97 98 99 100 101 102 103
    '#weight' => 30,
    '#tree' => TRUE,
    '#element_validate' => array('path_form_element_validate'),
  );
  $form['path']['alias'] = array(
    '#type' => 'textfield',
    '#title' => t('URL alias'),
    '#default_value' => $path['alias'],
    '#maxlength' => 255,
104
    '#description' => t('The alternative URL for this content. Use a relative path without a trailing slash. For example, enter "about" for the about page.'),
105 106 107
  );
  $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
  $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
108
  $form['path']['langcode'] = array('#type' => 'value', '#value' => $path['langcode']);
109
}
Steven Wittens's avatar
Steven Wittens committed
110

111
/**
112
 * Form element validation handler for URL alias form element.
113 114
 *
 * @see path_form_node_form_alter()
115
 */
116 117 118 119 120
function path_form_element_validate($element, &$form_state, $complete_form) {
  if (!empty($form_state['values']['path']['alias'])) {
    // Trim the submitted value.
    $alias = trim($form_state['values']['path']['alias']);
    form_set_value($element['alias'], $alias, $form_state);
121 122 123 124
    // Node language needs special care. Since the language of the URL alias
    // depends on the node language, and the node language can be switched
    // right within the same form, we need to conditionally overload the
    // originally assigned URL alias language.
125 126
    // @todo Remove this after converting Path module to a field, and, after
    //   stopping Locale module from abusing the content language system.
127 128
    if (isset($form_state['values']['langcode'])) {
      form_set_value($element['langcode'], $form_state['values']['langcode'], $form_state);
129
    }
130 131 132 133 134 135

    $path = $form_state['values']['path'];

    // Ensure that the submitted alias does not exist yet.
    $query = db_select('url_alias')
      ->condition('alias', $path['alias'])
136
      ->condition('langcode', $path['langcode']);
137 138 139 140 141 142
    if (!empty($path['source'])) {
      $query->condition('source', $path['source'], '<>');
    }
    $query->addExpression('1');
    $query->range(0, 1);
    if ($query->execute()->fetchField()) {
143
      form_error($element, $form_state, t('The alias is already in use.'));
144
    }
145 146
  }
}
Steven Wittens's avatar
Steven Wittens committed
147

148
/**
149
 * Implements hook_form_FORM_ID_alter() for taxonomy_term_form().
150
 */
151
function path_form_taxonomy_term_form_alter(&$form, $form_state) {
152
  $account = \Drupal::currentUser();
153 154
  // Make sure this does not show up on the delete confirmation form.
  if (empty($form_state['confirm_delete'])) {
155
    $term = $form_state['controller']->getEntity();
156
    $path = ($term->id() ? \Drupal::service('path.alias_storage')->load(array('source' => 'taxonomy/term/' . $term->id())) : array());
157 158
    if ($path === FALSE) {
      $path = array();
159
    }
160 161
    $path += array(
      'pid' => NULL,
162
      'source' => $term->id() ? 'taxonomy/term/' . $term->id() : NULL,
163
      'alias' => '',
164
      'langcode' => Language::LANGCODE_NOT_SPECIFIED,
165
    );
166
    $form['path'] = array(
167
      '#access' => $account->hasPermission('create url aliases') || $account->hasPermission('administer url aliases'),
168 169 170
      '#tree' => TRUE,
      '#element_validate' => array('path_form_element_validate'),
    );
171
    $form['path']['alias'] = array(
172 173
      '#type' => 'textfield',
      '#title' => t('URL alias'),
174
      '#default_value' => $path['alias'],
175 176 177 178
      '#maxlength' => 255,
      '#weight' => 0,
      '#description' => t("Optionally specify an alternative URL by which this term can be accessed. Use a relative path and don't add a trailing slash or the URL alias won't work."),
    );
179 180
    $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
    $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
181
    $form['path']['langcode'] = array('#type' => 'value', '#value' => $path['langcode']);
182 183 184
  }
}

185
/**
186
 * Implements hook_entity_base_field_info().
187
 */
188 189 190
function path_entity_base_field_info(EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') {
    $fields['path'] = FieldDefinition::create('path')
191 192 193
      ->setLabel(t('The path alias'))
      ->setComputed(TRUE);

194
    return $fields;
195 196
  }
}