updated core and modules
This commit is contained in:
@@ -20,5 +20,17 @@ process:
|
||||
langcode:
|
||||
plugin: d6_url_alias_language
|
||||
source: language
|
||||
node_translation:
|
||||
-
|
||||
plugin: explode
|
||||
source: src
|
||||
delimiter: /
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_translation
|
||||
destination:
|
||||
plugin: url_alias
|
||||
|
||||
@@ -18,5 +18,17 @@ process:
|
||||
- constants/slash
|
||||
- alias
|
||||
langcode: language
|
||||
node_translation:
|
||||
-
|
||||
plugin: explode
|
||||
source: source
|
||||
delimiter: /
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d7_node_translation
|
||||
destination:
|
||||
plugin: url_alias
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
*/
|
||||
function hook_path_insert($path) {
|
||||
db_insert('mytable')
|
||||
->fields(array(
|
||||
->fields([
|
||||
'alias' => $path['alias'],
|
||||
'pid' => $path['pid'],
|
||||
))
|
||||
])
|
||||
->execute();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ function hook_path_insert($path) {
|
||||
function hook_path_update($path) {
|
||||
if ($path['alias'] != $path['original']['alias']) {
|
||||
db_update('mytable')
|
||||
->fields(array('alias' => $path['alias']))
|
||||
->fields(['alias' => $path['alias']])
|
||||
->condition('pid', $path['pid'])
|
||||
->execute();
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ package: Core
|
||||
# core: 8.x
|
||||
configure: path.admin_overview
|
||||
|
||||
# Information added by Drupal.org packaging script on 2016-08-03
|
||||
version: '8.1.8'
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1470233791
|
||||
datestamp: 1502903957
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Update functions for the path module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Change the path field to computed for node and taxonomy_term.
|
||||
*/
|
||||
function path_update_8200() {
|
||||
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
foreach (['node', 'taxonomy_term'] as $entity_type_id) {
|
||||
if ($entity_definition_update_manager->getEntityType($entity_type_id)) {
|
||||
// Computed field definitions are not tracked by the entity definition
|
||||
// update manager, so remove them.
|
||||
$storage_definition = $entity_definition_update_manager->getFieldStorageDefinition('path', $entity_type_id);
|
||||
if ($storage_definition) {
|
||||
$entity_definition_update_manager->uninstallFieldStorageDefinition($storage_definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
* Enables users to rename URLs.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
@@ -19,13 +18,13 @@ function path_help($route_name, RouteMatchInterface $route_match) {
|
||||
case 'help.page.path':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$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 <a href=":path">online documentation for the Path module</a>.', array(':path' => 'https://www.drupal.org/documentation/modules/path', ':pathauto' => 'https://www.drupal.org/project/pathauto')) . '</p>';
|
||||
$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 <a href=":path">online documentation for the Path module</a>.', [':path' => 'https://www.drupal.org/documentation/modules/path', ':pathauto' => 'https://www.drupal.org/project/pathauto']) . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Creating aliases') . '</dt>';
|
||||
$output .= '<dd>' . t('If you create or edit a taxonomy term you can add an alias (for example <em>music/jazz</em>) in the field "URL alias". When creating or editing content you can add an alias (for example <em>about-us/team</em>) under the section "URL path settings" in the field "URL alias". Aliases for any other path can be added through the page <a href=":aliases">URL aliases</a>. To add aliases a user needs the permission <a href=":permissions">Create and edit URL aliases</a>.', array(':aliases' => \Drupal::url('path.admin_overview'), ':permissions' => \Drupal::url('user.admin_permissions', array(), array('fragment' => 'module-path')))) . '</dd>';
|
||||
$output .= '<dd>' . t('If you create or edit a taxonomy term you can add an alias (for example <em>music/jazz</em>) in the field "URL alias". When creating or editing content you can add an alias (for example <em>about-us/team</em>) under the section "URL path settings" in the field "URL alias". Aliases for any other path can be added through the page <a href=":aliases">URL aliases</a>. To add aliases a user needs the permission <a href=":permissions">Create and edit URL aliases</a>.', [':aliases' => \Drupal::url('path.admin_overview'), ':permissions' => \Drupal::url('user.admin_permissions', [], ['fragment' => 'module-path'])]) . '</dd>';
|
||||
$output .= '<dt>' . t('Managing aliases') . '</dt>';
|
||||
$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' => \Drupal::url('path.admin_overview'))) . '</dd>';
|
||||
$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.', [':aliases' => \Drupal::url('path.admin_overview')]) . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
|
||||
@@ -42,20 +41,20 @@ function path_help($route_name, RouteMatchInterface $route_match) {
|
||||
*/
|
||||
function path_form_node_form_alter(&$form, FormStateInterface $form_state) {
|
||||
$node = $form_state->getFormObject()->getEntity();
|
||||
$form['path_settings'] = array(
|
||||
$form['path_settings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => t('URL path settings'),
|
||||
'#open' => !empty($form['path']['widget'][0]['alias']['#value']),
|
||||
'#group' => 'advanced',
|
||||
'#access' => !empty($form['path']['#access']) && $node->hasField('path') && $node->get('path')->access('edit'),
|
||||
'#attributes' => array(
|
||||
'class' => array('path-form'),
|
||||
),
|
||||
'#attached' => array(
|
||||
'library' => array('path/drupal.path'),
|
||||
),
|
||||
'#attributes' => [
|
||||
'class' => ['path-form'],
|
||||
],
|
||||
'#attached' => [
|
||||
'library' => ['path/drupal.path'],
|
||||
],
|
||||
'#weight' => 30,
|
||||
);
|
||||
];
|
||||
$form['path']['#group'] = 'path_settings';
|
||||
}
|
||||
|
||||
@@ -67,24 +66,13 @@ function path_entity_base_field_info(EntityTypeInterface $entity_type) {
|
||||
$fields['path'] = BaseFieldDefinition::create('path')
|
||||
->setLabel(t('URL alias'))
|
||||
->setTranslatable(TRUE)
|
||||
->setDisplayOptions('form', array(
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'path',
|
||||
'weight' => 30,
|
||||
))
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setCustomStorage(TRUE);
|
||||
->setComputed(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_translation_delete().
|
||||
*/
|
||||
function path_entity_translation_delete(EntityInterface $translation) {
|
||||
if ($translation->hasLinkTemplate('canonical')) {
|
||||
$path = $translation->urlInfo()->getInternalPath();
|
||||
$conditions = array('source' => '/' . $path, 'langcode' => $translation->language()->getId());
|
||||
\Drupal::service('path.alias_storage')->delete($conditions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,63 +69,63 @@ class PathController extends ControllerBase {
|
||||
// alias with a language.
|
||||
$multilanguage = ($this->moduleHandler()->moduleExists('language') || $this->aliasStorage->languageAliasExists());
|
||||
|
||||
$header = array();
|
||||
$header[] = array('data' => $this->t('Alias'), 'field' => 'alias', 'sort' => 'asc');
|
||||
$header[] = array('data' => $this->t('System'), 'field' => 'source');
|
||||
$header = [];
|
||||
$header[] = ['data' => $this->t('Alias'), 'field' => 'alias', 'sort' => 'asc'];
|
||||
$header[] = ['data' => $this->t('System'), 'field' => 'source'];
|
||||
if ($multilanguage) {
|
||||
$header[] = array('data' => $this->t('Language'), 'field' => 'langcode');
|
||||
$header[] = ['data' => $this->t('Language'), 'field' => 'langcode'];
|
||||
}
|
||||
$header[] = $this->t('Operations');
|
||||
|
||||
$rows = array();
|
||||
$rows = [];
|
||||
$destination = $this->getDestinationArray();
|
||||
foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) {
|
||||
$row = array();
|
||||
$row = [];
|
||||
// @todo Should Path module store leading slashes? See
|
||||
// https://www.drupal.org/node/2430593.
|
||||
$row['data']['alias'] = $this->l(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUserInput($data->source, array(
|
||||
'attributes' => array('title' => $data->alias),
|
||||
)));
|
||||
$row['data']['source'] = $this->l(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUserInput($data->source, array(
|
||||
$row['data']['alias'] = $this->l(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUserInput($data->source, [
|
||||
'attributes' => ['title' => $data->alias],
|
||||
]));
|
||||
$row['data']['source'] = $this->l(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUserInput($data->source, [
|
||||
'alias' => TRUE,
|
||||
'attributes' => array('title' => $data->source),
|
||||
)));
|
||||
'attributes' => ['title' => $data->source],
|
||||
]));
|
||||
if ($multilanguage) {
|
||||
$row['data']['language_name'] = $this->languageManager()->getLanguageName($data->langcode);
|
||||
}
|
||||
|
||||
$operations = array();
|
||||
$operations['edit'] = array(
|
||||
$operations = [];
|
||||
$operations['edit'] = [
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => Url::fromRoute('path.admin_edit', ['pid' => $data->pid], ['query' => $destination]),
|
||||
);
|
||||
$operations['delete'] = array(
|
||||
];
|
||||
$operations['delete'] = [
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => Url::fromRoute('path.delete', ['pid' => $data->pid], ['query' => $destination]),
|
||||
);
|
||||
$row['data']['operations'] = array(
|
||||
'data' => array(
|
||||
];
|
||||
$row['data']['operations'] = [
|
||||
'data' => [
|
||||
'#type' => 'operations',
|
||||
'#links' => $operations,
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
// If the system path maps to a different URL alias, highlight this table
|
||||
// row to let the user know of old aliases.
|
||||
if ($data->alias != $this->aliasManager->getAliasByPath($data->source, $data->langcode)) {
|
||||
$row['class'] = array('warning');
|
||||
$row['class'] = ['warning'];
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['path_table'] = array(
|
||||
$build['path_table'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
'#empty' => $this->t('No URL aliases available. <a href=":link">Add URL alias</a>.', array(':link' => $this->url('path.admin_add'))),
|
||||
);
|
||||
$build['path_pager'] = array('#type' => 'pager');
|
||||
'#empty' => $this->t('No URL aliases available. <a href=":link">Add URL alias</a>.', [':link' => $this->url('path.admin_add')]),
|
||||
];
|
||||
$build['path_pager'] = ['#type' => 'pager'];
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ class AddForm extends PathFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildPath($pid) {
|
||||
return array(
|
||||
return [
|
||||
'source' => '',
|
||||
'alias' => '',
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'pid' => NULL,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class DeleteForm extends ConfirmFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return t('Are you sure you want to delete path alias %title?', array('%title' => $this->pathAlias['alias']));
|
||||
return t('Are you sure you want to delete path alias %title?', ['%title' => $this->pathAlias['alias']]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,7 @@ class DeleteForm extends ConfirmFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
|
||||
$this->pathAlias = $this->aliasStorage->load(array('pid' => $pid));
|
||||
$this->pathAlias = $this->aliasStorage->load(['pid' => $pid]);
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
@@ -82,7 +82,7 @@ class DeleteForm extends ConfirmFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->aliasStorage->delete(array('pid' => $this->pathAlias['pid']));
|
||||
$this->aliasStorage->delete(['pid' => $this->pathAlias['pid']]);
|
||||
|
||||
$form_state->setRedirect('path.admin_overview');
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class EditForm extends PathFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildPath($pid) {
|
||||
return $this->aliasStorage->load(array('pid' => $pid));
|
||||
return $this->aliasStorage->load(['pid' => $pid]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,27 +31,27 @@ class EditForm extends PathFormBase {
|
||||
$form = parent::buildForm($form, $form_state, $pid);
|
||||
|
||||
$form['#title'] = $this->path['alias'];
|
||||
$form['pid'] = array(
|
||||
$form['pid'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $this->path['pid'],
|
||||
);
|
||||
];
|
||||
|
||||
$url = new Url('path.delete', array(
|
||||
$url = new Url('path.delete', [
|
||||
'pid' => $this->path['pid'],
|
||||
));
|
||||
]);
|
||||
|
||||
if ($this->getRequest()->query->has('destination')) {
|
||||
$url->setOption('query', $this->getDestinationArray());
|
||||
}
|
||||
|
||||
$form['actions']['delete'] = array(
|
||||
$form['actions']['delete'] = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Delete'),
|
||||
'#url' => $url,
|
||||
'#attributes' => array(
|
||||
'class' => array('button', 'button--danger'),
|
||||
),
|
||||
);
|
||||
'#attributes' => [
|
||||
'class' => ['button', 'button--danger'],
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
@@ -21,32 +21,31 @@ class PathFilterForm extends FormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $keys = NULL) {
|
||||
$form['#attributes'] = array('class' => array('search-form'));
|
||||
$form['basic'] = array(
|
||||
$form['#attributes'] = ['class' => ['search-form']];
|
||||
$form['basic'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Filter aliases'),
|
||||
'#open' => TRUE,
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
);
|
||||
$form['basic']['filter'] = array(
|
||||
'#attributes' => ['class' => ['container-inline']],
|
||||
];
|
||||
$form['basic']['filter'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => 'Path alias',
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $keys,
|
||||
'#maxlength' => 128,
|
||||
'#size' => 25,
|
||||
);
|
||||
$form['basic']['submit'] = array(
|
||||
];
|
||||
$form['basic']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#button_type' => 'primary',
|
||||
'#value' => $this->t('Filter'),
|
||||
);
|
||||
];
|
||||
if ($keys) {
|
||||
$form['basic']['reset'] = array(
|
||||
$form['basic']['reset'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Reset'),
|
||||
'#submit' => array('::resetForm'),
|
||||
);
|
||||
'#submit' => ['::resetForm'],
|
||||
];
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
@@ -55,9 +54,9 @@ class PathFilterForm extends FormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirect('path.admin_overview_filter', array(), array(
|
||||
'query' => array('search' => trim($form_state->getValue('filter'))),
|
||||
));
|
||||
$form_state->setRedirect('path.admin_overview_filter', [], [
|
||||
'query' => ['search' => trim($form_state->getValue('filter'))],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,7 +95,7 @@ abstract class PathFormBase extends FormBase {
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
|
||||
$this->path = $this->buildPath($pid);
|
||||
$form['source'] = array(
|
||||
$form['source'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Existing system path'),
|
||||
'#default_value' => $this->path['source'],
|
||||
@@ -104,27 +104,27 @@ abstract class PathFormBase extends FormBase {
|
||||
'#description' => $this->t('Specify the existing path you wish to alias. For example: /node/28, /forum/1, /taxonomy/term/1.'),
|
||||
'#field_prefix' => $this->requestContext->getCompleteBaseUrl(),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['alias'] = array(
|
||||
];
|
||||
$form['alias'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Path alias'),
|
||||
'#default_value' => $this->path['alias'],
|
||||
'#maxlength' => 255,
|
||||
'#size' => 45,
|
||||
'#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page. Use a relative path with a slash in front.'),
|
||||
'#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page.'),
|
||||
'#field_prefix' => $this->requestContext->getCompleteBaseUrl(),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
];
|
||||
|
||||
// A hidden value unless language.module is enabled.
|
||||
if (\Drupal::moduleHandler()->moduleExists('language')) {
|
||||
$languages = \Drupal::languageManager()->getLanguages();
|
||||
$language_options = array();
|
||||
$language_options = [];
|
||||
foreach ($languages as $langcode => $language) {
|
||||
$language_options[$langcode] = $language->getName();
|
||||
}
|
||||
|
||||
$form['langcode'] = array(
|
||||
$form['langcode'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Language'),
|
||||
'#options' => $language_options,
|
||||
@@ -133,21 +133,21 @@ abstract class PathFormBase extends FormBase {
|
||||
'#default_value' => $this->path['langcode'],
|
||||
'#weight' => -10,
|
||||
'#description' => $this->t('A path alias set for a specific language will always be used when displaying this page in that language, and takes precedence over path aliases set as <em>- None -</em>.'),
|
||||
);
|
||||
];
|
||||
}
|
||||
else {
|
||||
$form['langcode'] = array(
|
||||
$form['langcode'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $this->path['langcode']
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
$form['actions'] = ['#type' => 'actions'];
|
||||
$form['actions']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ abstract class PathFormBase extends FormBase {
|
||||
|
||||
|
||||
if (!$this->pathValidator->isValid(trim($source, '/'))) {
|
||||
$form_state->setErrorByName('source', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $source)));
|
||||
$form_state->setErrorByName('source', t("The path '@link_path' is either invalid or you do not have access to it.", ['@link_path' => $source]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,4 +21,17 @@ class PathFieldItemList extends FieldItemList {
|
||||
return AccessResult::allowedIfHasPermissions($account, ['create url aliases', 'administer url aliases'], 'OR')->cachePerPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete() {
|
||||
// Delete all aliases associated with this entity in the current language.
|
||||
$entity = $this->getEntity();
|
||||
$conditions = [
|
||||
'source' => '/' . $entity->toUrl()->getInternalPath(),
|
||||
'langcode' => $entity->language()->getId(),
|
||||
];
|
||||
\Drupal::service('path.alias_storage')->delete($conditions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class PathItem extends FieldItemBase {
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['alias'] = DataDefinition::create('string')
|
||||
->setLabel(t('Path alias'));
|
||||
$properties['pid'] = DataDefinition::create('string')
|
||||
$properties['pid'] = DataDefinition::create('integer')
|
||||
->setLabel(t('Path id'));
|
||||
return $properties;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class PathItem extends FieldItemBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ class PathItem extends FieldItemBase {
|
||||
else {
|
||||
// Delete old alias if user erased it.
|
||||
if ($this->pid && !$this->alias) {
|
||||
\Drupal::service('path.alias_storage')->delete(array('pid' => $this->pid));
|
||||
\Drupal::service('path.alias_storage')->delete(['pid' => $this->pid]);
|
||||
}
|
||||
// Only save a non-empty alias.
|
||||
elseif ($this->alias) {
|
||||
@@ -72,15 +72,6 @@ class PathItem extends FieldItemBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete() {
|
||||
// Delete all aliases associated with this entity.
|
||||
$entity = $this->getEntity();
|
||||
\Drupal::service('path.alias_storage')->delete(array('source' => '/' . $entity->urlInfo()->getInternalPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -26,47 +26,47 @@ class PathWidget extends WidgetBase {
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
$entity = $items->getEntity();
|
||||
$path = array();
|
||||
$path = [];
|
||||
if (!$entity->isNew()) {
|
||||
$conditions = array('source' => '/' . $entity->urlInfo()->getInternalPath());
|
||||
$conditions = ['source' => '/' . $entity->urlInfo()->getInternalPath()];
|
||||
if ($items->getLangcode() != LanguageInterface::LANGCODE_NOT_SPECIFIED) {
|
||||
$conditions['langcode'] = $items->getLangcode();
|
||||
}
|
||||
$path = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
if ($path === FALSE) {
|
||||
$path = array();
|
||||
$path = [];
|
||||
}
|
||||
}
|
||||
$path += array(
|
||||
$path += [
|
||||
'pid' => NULL,
|
||||
'source' => !$entity->isNew() ? '/' . $entity->urlInfo()->getInternalPath() : NULL,
|
||||
'alias' => '',
|
||||
'langcode' => $items->getLangcode(),
|
||||
);
|
||||
];
|
||||
|
||||
$element += array(
|
||||
'#element_validate' => array(array(get_class($this), 'validateFormElement')),
|
||||
);
|
||||
$element['alias'] = array(
|
||||
$element += [
|
||||
'#element_validate' => [[get_class($this), 'validateFormElement']],
|
||||
];
|
||||
$element['alias'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $element['#title'],
|
||||
'#default_value' => $path['alias'],
|
||||
'#required' => $element['#required'],
|
||||
'#maxlength' => 255,
|
||||
'#description' => $this->t('The alternative URL for this content. Use a relative path. For example, enter "/about" for the about page.'),
|
||||
);
|
||||
$element['pid'] = array(
|
||||
'#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page.'),
|
||||
];
|
||||
$element['pid'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $path['pid'],
|
||||
);
|
||||
$element['source'] = array(
|
||||
];
|
||||
$element['source'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $path['source'],
|
||||
);
|
||||
$element['langcode'] = array(
|
||||
];
|
||||
$element['langcode'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $path['langcode'],
|
||||
);
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
||||
@@ -87,12 +87,12 @@ class PathWidget extends WidgetBase {
|
||||
// Validate that the submitted alias does not exist yet.
|
||||
$is_exists = \Drupal::service('path.alias_storage')->aliasExists($alias, $element['langcode']['#value'], $element['source']['#value']);
|
||||
if ($is_exists) {
|
||||
$form_state->setError($element, t('The alias is already in use.'));
|
||||
$form_state->setError($element['alias'], t('The alias is already in use.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($alias && $alias[0] !== '/') {
|
||||
$form_state->setError($element, t('The alias needs to start with a slash.'));
|
||||
$form_state->setError($element['alias'], t('The alias needs to start with a slash.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +58,24 @@ class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterfac
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
public function import(Row $row, array $old_destination_id_values = []) {
|
||||
$source = $row->getDestinationProperty('source');
|
||||
$alias = $row->getDestinationProperty('alias');
|
||||
$langcode = $row->getDestinationProperty('langcode');
|
||||
$pid = $old_destination_id_values ? $old_destination_id_values[0] : NULL;
|
||||
|
||||
$path = $this->aliasStorage->save(
|
||||
$row->getDestinationProperty('source'),
|
||||
$row->getDestinationProperty('alias'),
|
||||
$row->getDestinationProperty('langcode'),
|
||||
$old_destination_id_values ? $old_destination_id_values[0] : NULL
|
||||
);
|
||||
// Check if this alias is for a node and if that node is a translation.
|
||||
if (preg_match('/^\/node\/\d+$/', $source) && $row->hasDestinationProperty('node_translation')) {
|
||||
|
||||
return array($path['pid']);
|
||||
// Replace the alias source with the translation source path.
|
||||
$node_translation = $row->getDestinationProperty('node_translation');
|
||||
$source = '/node/' . $node_translation[0];
|
||||
$langcode = $node_translation[1];
|
||||
}
|
||||
|
||||
$path = $this->aliasStorage->save($source, $alias, $langcode, $pid);
|
||||
|
||||
return [$path['pid']];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,17 +13,21 @@ abstract class UrlAliasBase extends DrupalSqlBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return $this->select('url_alias', 'ua')->fields('ua');
|
||||
// The order of the migration is significant since
|
||||
// \Drupal\Core\Path\AliasStorage::lookupPathAlias() orders by pid before
|
||||
// returning a result. Postgres does not automatically order by primary key
|
||||
// therefore we need to add a specific order by.
|
||||
return $this->select('url_alias', 'ua')->fields('ua')->orderBy('pid');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return array(
|
||||
return [
|
||||
'pid' => $this->t('The numeric identifier of the path alias.'),
|
||||
'language' => $this->t('The language code of the URL alias.'),
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,9 @@ use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Provides a base class for testing the Path module.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\path\Functional\PathTestBase instead.
|
||||
*/
|
||||
abstract class PathTestBase extends WebTestBase {
|
||||
|
||||
@@ -14,15 +17,15 @@ abstract class PathTestBase extends WebTestBase {
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'path');
|
||||
public static $modules = ['node', 'path'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create Basic page and Article node types.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
/**
|
||||
* Tests the Path admin UI.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathAdminTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['path'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(['create page content', 'edit own page content', 'administer url aliases', 'create url aliases']);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the filtering aspect of the Path UI.
|
||||
*/
|
||||
public function testPathFiltering() {
|
||||
// Create test nodes.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
$node2 = $this->drupalCreateNode();
|
||||
$node3 = $this->drupalCreateNode();
|
||||
|
||||
// Create aliases.
|
||||
$alias1 = '/' . $this->randomMachineName(8);
|
||||
$edit = [
|
||||
'source' => '/node/' . $node1->id(),
|
||||
'alias' => $alias1,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$alias2 = '/' . $this->randomMachineName(8);
|
||||
$edit = [
|
||||
'source' => '/node/' . $node2->id(),
|
||||
'alias' => $alias2,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$alias3 = '/' . $this->randomMachineName(4) . '/' . $this->randomMachineName(4);
|
||||
$edit = [
|
||||
'source' => '/node/' . $node3->id(),
|
||||
'alias' => $alias3,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Filter by the first alias.
|
||||
$edit = [
|
||||
'filter' => $alias1,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertLinkByHref($alias1);
|
||||
$this->assertNoLinkByHref($alias2);
|
||||
$this->assertNoLinkByHref($alias3);
|
||||
|
||||
// Filter by the second alias.
|
||||
$edit = [
|
||||
'filter' => $alias2,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertNoLinkByHref($alias1);
|
||||
$this->assertLinkByHref($alias2);
|
||||
$this->assertNoLinkByHref($alias3);
|
||||
|
||||
// Filter by the third alias which has a slash.
|
||||
$edit = [
|
||||
'filter' => $alias3,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertNoLinkByHref($alias1);
|
||||
$this->assertNoLinkByHref($alias2);
|
||||
$this->assertLinkByHref($alias3);
|
||||
|
||||
// Filter by a random string with a different length.
|
||||
$edit = [
|
||||
'filter' => $this->randomMachineName(10),
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertNoLinkByHref($alias1);
|
||||
$this->assertNoLinkByHref($alias2);
|
||||
|
||||
// Reset the filter.
|
||||
$edit = [];
|
||||
$this->drupalPostForm(NULL, $edit, t('Reset'));
|
||||
$this->assertLinkByHref($alias1);
|
||||
$this->assertLinkByHref($alias2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Add, edit, delete, and change alias and verify its consistency in the
|
||||
* database.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathAliasTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['path'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(['create page content', 'edit own page content', 'administer url aliases', 'create url aliases']);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the path cache.
|
||||
*/
|
||||
public function testPathCache() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = [];
|
||||
$edit['source'] = '/node/' . $node1->id();
|
||||
$edit['alias'] = '/' . $this->randomMachineName(8);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Check the path alias whitelist cache.
|
||||
$whitelist = \Drupal::cache('bootstrap')->get('path_alias_whitelist');
|
||||
$this->assertTrue($whitelist->data['node']);
|
||||
$this->assertFalse($whitelist->data['admin']);
|
||||
|
||||
// Visit the system path for the node and confirm a cache entry is
|
||||
// created.
|
||||
\Drupal::cache('data')->deleteAll();
|
||||
// Make sure the path is not converted to the alias.
|
||||
$this->drupalGet(trim($edit['source'], '/'), ['alias' => TRUE]);
|
||||
$this->assertTrue(\Drupal::cache('data')->get('preload-paths:' . $edit['source']), 'Cache entry was created.');
|
||||
|
||||
// Visit the alias for the node and confirm a cache entry is created.
|
||||
\Drupal::cache('data')->deleteAll();
|
||||
// @todo Remove this once https://www.drupal.org/node/2480077 lands.
|
||||
Cache::invalidateTags(['rendered']);
|
||||
$this->drupalGet(trim($edit['alias'], '/'));
|
||||
$this->assertTrue(\Drupal::cache('data')->get('preload-paths:' . $edit['source']), 'Cache entry was created.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alias functionality through the admin interfaces.
|
||||
*/
|
||||
public function testAdminAlias() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = [];
|
||||
$edit['source'] = '/node/' . $node1->id();
|
||||
$edit['alias'] = '/' . $this->getRandomGenerator()->word(8);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($edit['alias']);
|
||||
$this->assertText($node1->label(), 'Alias works.');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that the alias works in a case-insensitive way.
|
||||
$this->assertTrue(ctype_lower(ltrim($edit['alias'], '/')));
|
||||
$this->drupalGet($edit['alias']);
|
||||
$this->assertText($node1->label(), 'Alias works lower case.');
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet(Unicode::strtoupper($edit['alias']));
|
||||
$this->assertText($node1->label(), 'Alias works upper case.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Change alias to one containing "exotic" characters.
|
||||
$pid = $this->getPID($edit['alias']);
|
||||
|
||||
$previous = $edit['alias'];
|
||||
$edit['alias'] = '/alias' . // Lower-case letters.
|
||||
// "Special" ASCII characters.
|
||||
"- ._~!$'\"()*@[]?&+%#,;=:" .
|
||||
// Characters that look like a percent-escaped string.
|
||||
"%23%25%26%2B%2F%3F" .
|
||||
// Characters from various non-ASCII alphabets.
|
||||
"中國書۞";
|
||||
$connection = Database::getConnection();
|
||||
if ($connection->databaseType() != 'sqlite') {
|
||||
// When using LIKE for case-insensitivity, the SQLite driver is
|
||||
// currently unable to find the upper-case versions of non-ASCII
|
||||
// characters.
|
||||
// @todo fix this in https://www.drupal.org/node/2607432
|
||||
$edit['alias'] .= "ïвβéø";
|
||||
}
|
||||
$this->drupalPostForm('admin/config/search/path/edit/' . $pid, $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet(Unicode::strtoupper($edit['alias']));
|
||||
$this->assertText($node1->label(), 'Changed alias works.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->container->get('path.alias_manager')->cacheClear();
|
||||
// Confirm that previous alias no longer works.
|
||||
$this->drupalGet($previous);
|
||||
$this->assertNoText($node1->label(), 'Previous alias no longer works.');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Create second test node.
|
||||
$node2 = $this->drupalCreateNode();
|
||||
|
||||
// Set alias to second test node.
|
||||
$edit['source'] = '/node/' . $node2->id();
|
||||
// leave $edit['alias'] the same
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Confirm no duplicate was created.
|
||||
$this->assertRaw(t('The alias %alias is already in use in this language.', ['%alias' => $edit['alias']]), 'Attempt to move alias was rejected.');
|
||||
|
||||
$edit_upper = $edit;
|
||||
$edit_upper['alias'] = Unicode::strtoupper($edit['alias']);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit_upper, t('Save'));
|
||||
$this->assertRaw(t('The alias %alias could not be added because it is already in use in this language with different capitalization: %stored_alias.', [
|
||||
'%alias' => $edit_upper['alias'],
|
||||
'%stored_alias' => $edit['alias'],
|
||||
]), 'Attempt to move upper-case alias was rejected.');
|
||||
|
||||
// Delete alias.
|
||||
$this->drupalGet('admin/config/search/path/edit/' . $pid);
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertRaw(t('Are you sure you want to delete path alias %name?', ['%name' => $edit['alias']]));
|
||||
$this->drupalPostForm(NULL, [], t('Confirm'));
|
||||
|
||||
// Confirm that the alias no longer works.
|
||||
$this->drupalGet($edit['alias']);
|
||||
$this->assertNoText($node1->label(), 'Alias was successfully deleted.');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Create a really long alias.
|
||||
$edit = [];
|
||||
$edit['source'] = '/node/' . $node1->id();
|
||||
$alias = '/' . $this->randomMachineName(128);
|
||||
$edit['alias'] = $alias;
|
||||
// The alias is shortened to 50 characters counting the ellipsis.
|
||||
$truncated_alias = substr($alias, 0, 47);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
$this->assertNoText($alias, 'The untruncated alias was not found.');
|
||||
// The 'truncated' alias will always be found.
|
||||
$this->assertText($truncated_alias, 'The truncated alias was found.');
|
||||
|
||||
// Create third test node.
|
||||
$node3 = $this->drupalCreateNode();
|
||||
|
||||
// Create absolute path alias.
|
||||
$edit = [];
|
||||
$edit['source'] = '/node/' . $node3->id();
|
||||
$node3_alias = '/' . $this->randomMachineName(8);
|
||||
$edit['alias'] = $node3_alias;
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Create fourth test node.
|
||||
$node4 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias with trailing slash.
|
||||
$edit = [];
|
||||
$edit['source'] = '/node/' . $node4->id();
|
||||
$node4_alias = '/' . $this->randomMachineName(8);
|
||||
$edit['alias'] = $node4_alias . '/';
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias with trailing slash is not found.
|
||||
$this->assertNoText($edit['alias'], 'The absolute alias was not found.');
|
||||
// The alias without trailing flash is found.
|
||||
$this->assertText(trim($edit['alias'], '/'), 'The alias without trailing slash was found.');
|
||||
|
||||
// Update an existing alias to point to a different source.
|
||||
$pid = $this->getPID($node4_alias);
|
||||
$edit = [];
|
||||
$edit['alias'] = $node4_alias;
|
||||
$edit['source'] = '/node/' . $node2->id();
|
||||
$this->drupalPostForm('admin/config/search/path/edit/' . $pid, $edit, t('Save'));
|
||||
$this->assertText('The alias has been saved.');
|
||||
$this->drupalGet($edit['alias']);
|
||||
$this->assertNoText($node4->label(), 'Previous alias no longer works.');
|
||||
$this->assertText($node2->label(), 'Alias works.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Update an existing alias to use a duplicate alias.
|
||||
$pid = $this->getPID($node3_alias);
|
||||
$edit = [];
|
||||
$edit['alias'] = $node4_alias;
|
||||
$edit['source'] = '/node/' . $node3->id();
|
||||
$this->drupalPostForm('admin/config/search/path/edit/' . $pid, $edit, t('Save'));
|
||||
$this->assertRaw(t('The alias %alias is already in use in this language.', ['%alias' => $edit['alias']]));
|
||||
|
||||
// Create an alias without a starting slash.
|
||||
$node5 = $this->drupalCreateNode();
|
||||
|
||||
$edit = [];
|
||||
$edit['source'] = 'node/' . $node5->id();
|
||||
$node5_alias = $this->randomMachineName(8);
|
||||
$edit['alias'] = $node5_alias . '/';
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$this->assertUrl('admin/config/search/path/add');
|
||||
$this->assertText('The source path has to start with a slash.');
|
||||
$this->assertText('The alias path has to start with a slash.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alias functionality through the node interfaces.
|
||||
*/
|
||||
public function testNodeAlias() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = [];
|
||||
$edit['path[0][alias]'] = '/' . $this->randomMachineName(8);
|
||||
$this->drupalPostForm('node/' . $node1->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($edit['path[0][alias]']);
|
||||
$this->assertText($node1->label(), 'Alias works.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Confirm the 'canonical' and 'shortlink' URLs.
|
||||
$elements = $this->xpath("//link[contains(@rel, 'canonical') and contains(@href, '" . $edit['path[0][alias]'] . "')]");
|
||||
$this->assertTrue(!empty($elements), 'Page contains canonical link URL.');
|
||||
$elements = $this->xpath("//link[contains(@rel, 'shortlink') and contains(@href, 'node/" . $node1->id() . "')]");
|
||||
$this->assertTrue(!empty($elements), 'Page contains shortlink URL.');
|
||||
|
||||
$previous = $edit['path[0][alias]'];
|
||||
// Change alias to one containing "exotic" characters.
|
||||
$edit['path[0][alias]'] = '/alias' . // Lower-case letters.
|
||||
// "Special" ASCII characters.
|
||||
"- ._~!$'\"()*@[]?&+%#,;=:" .
|
||||
// Characters that look like a percent-escaped string.
|
||||
"%23%25%26%2B%2F%3F" .
|
||||
// Characters from various non-ASCII alphabets.
|
||||
"中國書۞";
|
||||
$connection = Database::getConnection();
|
||||
if ($connection->databaseType() != 'sqlite') {
|
||||
// When using LIKE for case-insensitivity, the SQLite driver is
|
||||
// currently unable to find the upper-case versions of non-ASCII
|
||||
// characters.
|
||||
// @todo fix this in https://www.drupal.org/node/2607432
|
||||
$edit['path[0][alias]'] .= "ïвβéø";
|
||||
}
|
||||
$this->drupalPostForm('node/' . $node1->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet(Unicode::strtoupper($edit['path[0][alias]']));
|
||||
$this->assertText($node1->label(), 'Changed alias works.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Make sure that previous alias no longer works.
|
||||
$this->drupalGet($previous);
|
||||
$this->assertNoText($node1->label(), 'Previous alias no longer works.');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Create second test node.
|
||||
$node2 = $this->drupalCreateNode();
|
||||
|
||||
// Set alias to second test node.
|
||||
// Leave $edit['path[0][alias]'] the same.
|
||||
$this->drupalPostForm('node/' . $node2->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias didn't make a duplicate.
|
||||
$this->assertText(t('The alias is already in use.'), 'Attempt to moved alias was rejected.');
|
||||
|
||||
// Delete alias.
|
||||
$this->drupalPostForm('node/' . $node1->id() . '/edit', ['path[0][alias]' => ''], t('Save'));
|
||||
|
||||
// Confirm that the alias no longer works.
|
||||
$this->drupalGet($edit['path[0][alias]']);
|
||||
$this->assertNoText($node1->label(), 'Alias was successfully deleted.');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Create third test node.
|
||||
$node3 = $this->drupalCreateNode();
|
||||
|
||||
// Set its path alias to an absolute path.
|
||||
$edit = ['path[0][alias]' => '/' . $this->randomMachineName(8)];
|
||||
$this->drupalPostForm('node/' . $node3->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias was converted to a relative path.
|
||||
$this->drupalGet(trim($edit['path[0][alias]'], '/'));
|
||||
$this->assertText($node3->label(), 'Alias became relative.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Create fourth test node.
|
||||
$node4 = $this->drupalCreateNode();
|
||||
|
||||
// Set its path alias to have a trailing slash.
|
||||
$edit = ['path[0][alias]' => '/' . $this->randomMachineName(8) . '/'];
|
||||
$this->drupalPostForm('node/' . $node4->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias was converted to a relative path.
|
||||
$this->drupalGet(trim($edit['path[0][alias]'], '/'));
|
||||
$this->assertText($node4->label(), 'Alias trimmed trailing slash.');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Create fifth test node.
|
||||
$node5 = $this->drupalCreateNode();
|
||||
|
||||
// Set a path alias.
|
||||
$edit = ['path[0][alias]' => '/' . $this->randomMachineName(8)];
|
||||
$this->drupalPostForm('node/' . $node5->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Delete the node and check that the path alias is also deleted.
|
||||
$node5->delete();
|
||||
$path_alias = \Drupal::service('path.alias_storage')->lookupPathAlias('/node/' . $node5->id(), $node5->language()->getId());
|
||||
$this->assertFalse($path_alias, 'Alias was successfully deleted when the referenced node was deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path ID.
|
||||
*
|
||||
* @param string $alias
|
||||
* A string containing an aliased path.
|
||||
*
|
||||
* @return int
|
||||
* Integer representing the path ID.
|
||||
*/
|
||||
public function getPID($alias) {
|
||||
return db_query("SELECT pid FROM {url_alias} WHERE alias = :alias", [':alias' => $alias])->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that duplicate aliases fail validation.
|
||||
*/
|
||||
public function testDuplicateNodeAlias() {
|
||||
// Create one node with a random alias.
|
||||
$node_one = $this->drupalCreateNode();
|
||||
$edit = [];
|
||||
$edit['path[0][alias]'] = '/' . $this->randomMachineName();
|
||||
$this->drupalPostForm('node/' . $node_one->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Now create another node and try to set the same alias.
|
||||
$node_two = $this->drupalCreateNode();
|
||||
$this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertText(t('The alias is already in use.'));
|
||||
$this->assertFieldByXPath("//input[@name='path[0][alias]' and contains(@class, 'error')]", $edit['path[0][alias]'], 'Textfield exists and has the error class.');
|
||||
|
||||
// Behavior here differs with the inline_form_errors module enabled.
|
||||
// Enable the inline_form_errors module and try this again. This module
|
||||
// improves validation with a link in the error message(s) to the fields
|
||||
// which have invalid input.
|
||||
$this->assertTrue($this->container->get('module_installer')->install(['inline_form_errors'], TRUE), 'Installed inline_form_errors.');
|
||||
// Attempt to edit the second node again, as before.
|
||||
$this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Preview'));
|
||||
// This error should still be present next to the field.
|
||||
$this->assertSession()->pageTextContains(t('The alias is already in use.'), 'Field error found with expected text.');
|
||||
// The validation error set for the page should include this text.
|
||||
$this->assertSession()->pageTextContains(t('1 error has been found: URL alias'), 'Form error found with expected text.');
|
||||
// The text 'URL alias' should be a link.
|
||||
$this->assertSession()->linkExists('URL alias');
|
||||
// The link should be to the ID of the URL alias field.
|
||||
$this->assertSession()->linkByHrefExists('#edit-path-0-alias');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
/**
|
||||
* Confirm that paths work with translated nodes.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathLanguageTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['path', 'locale', 'locale_test', 'content_translation'];
|
||||
|
||||
/**
|
||||
* An user with permissions to administer content types.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$permissions = [
|
||||
'access administration pages',
|
||||
'administer content translation',
|
||||
'administer content types',
|
||||
'administer languages',
|
||||
'administer url aliases',
|
||||
'create content translations',
|
||||
'create page content',
|
||||
'create url aliases',
|
||||
'edit any page content',
|
||||
'translate any entity',
|
||||
];
|
||||
// Create and log in user.
|
||||
$this->webUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->webUser);
|
||||
|
||||
// Enable French language.
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => 1];
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
|
||||
// Enable translation for page node.
|
||||
$edit = [
|
||||
'entity_types[node]' => 1,
|
||||
'settings[node][page][translatable]' => 1,
|
||||
'settings[node][page][fields][path]' => 1,
|
||||
'settings[node][page][fields][body]' => 1,
|
||||
'settings[node][page][settings][language][language_alterable]' => 1,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
\Drupal::entityManager()->clearCachedDefinitions();
|
||||
|
||||
$definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'page');
|
||||
$this->assertTrue($definitions['path']->isTranslatable(), 'Node path is translatable.');
|
||||
$this->assertTrue($definitions['body']->isTranslatable(), 'Node body is translatable.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test alias functionality through the admin interfaces.
|
||||
*/
|
||||
public function testAliasTranslation() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$english_node = $this->drupalCreateNode(['type' => 'page', 'langcode' => 'en']);
|
||||
$english_alias = $this->randomMachineName();
|
||||
|
||||
// Edit the node to set language and path.
|
||||
$edit = [];
|
||||
$edit['path[0][alias]'] = '/' . $english_alias;
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($english_alias);
|
||||
$this->assertText($english_node->body->value, 'Alias works.');
|
||||
|
||||
// Translate the node into French.
|
||||
$this->drupalGet('node/' . $english_node->id() . '/translations');
|
||||
$this->clickLink(t('Add'));
|
||||
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
$french_alias = $this->randomMachineName();
|
||||
$edit['path[0][alias]'] = '/' . $french_alias;
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
|
||||
// Clear the path lookup cache.
|
||||
$this->container->get('path.alias_manager')->cacheClear();
|
||||
|
||||
// Languages are cached on many levels, and we need to clear those caches.
|
||||
$this->container->get('language_manager')->reset();
|
||||
$this->rebuildContainer();
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
// Ensure the node was created.
|
||||
$node_storage->resetCache([$english_node->id()]);
|
||||
$english_node = $node_storage->load($english_node->id());
|
||||
$english_node_french_translation = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($english_node->hasTranslation('fr'), 'Node found in database.');
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet('fr' . $edit['path[0][alias]']);
|
||||
$this->assertText($english_node_french_translation->body->value, 'Alias for French translation works.');
|
||||
|
||||
// Confirm that the alias is returned for the URL. Languages are cached on
|
||||
// many levels, and we need to clear those caches.
|
||||
$this->container->get('language_manager')->reset();
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
$url = $english_node_french_translation->url('canonical', ['language' => $languages['fr']]);
|
||||
|
||||
$this->assertTrue(strpos($url, $edit['path[0][alias]']), 'URL contains the path alias.');
|
||||
|
||||
// Confirm that the alias works even when changing language negotiation
|
||||
// options. Enable User language detection and selection over URL one.
|
||||
$edit = [
|
||||
'language_interface[enabled][language-user]' => 1,
|
||||
'language_interface[weight][language-user]' => -9,
|
||||
'language_interface[enabled][language-url]' => 1,
|
||||
'language_interface[weight][language-url]' => -8,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
|
||||
// Change user language preference.
|
||||
$edit = ['preferred_langcode' => 'fr'];
|
||||
$this->drupalPostForm("user/" . $this->webUser->id() . "/edit", $edit, t('Save'));
|
||||
|
||||
// Check that the English alias works. In this situation French is the
|
||||
// current UI and content language, while URL language is English (since we
|
||||
// do not have a path prefix we fall back to the site's default language).
|
||||
// We need to ensure that the user language preference is not taken into
|
||||
// account while determining the path alias language, because if this
|
||||
// happens we have no way to check that the path alias is valid: there is no
|
||||
// path alias for French matching the english alias. So the alias manager
|
||||
// needs to use the URL language to check whether the alias is valid.
|
||||
$this->drupalGet($english_alias);
|
||||
$this->assertText($english_node_french_translation->body->value, 'English alias, but French preferred by the user: French translation.');
|
||||
|
||||
// Check that the French alias works.
|
||||
$this->drupalGet("fr/$french_alias");
|
||||
$this->assertText($english_node_french_translation->body->value, 'Alias for French translation works.');
|
||||
|
||||
// Disable URL language negotiation.
|
||||
$edit = ['language_interface[enabled][language-url]' => FALSE];
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
|
||||
// Check that the English alias still works.
|
||||
$this->drupalGet($english_alias);
|
||||
$this->assertText($english_node_french_translation->body->value, 'English alias, but French preferred by the user: French translation.');
|
||||
|
||||
// Check that the French alias is not available. We check the unprefixed
|
||||
// alias because we disabled URL language negotiation above. In this
|
||||
// situation only aliases in the default language and language neutral ones
|
||||
// should keep working.
|
||||
$this->drupalGet($french_alias);
|
||||
$this->assertResponse(404, 'Alias for French translation is unavailable when URL language negotiation is disabled.');
|
||||
|
||||
// The alias manager has an internal path lookup cache. Check to see that
|
||||
// it has the appropriate contents at this point.
|
||||
$this->container->get('path.alias_manager')->cacheClear();
|
||||
$french_node_path = $this->container->get('path.alias_manager')->getPathByAlias('/' . $french_alias, 'fr');
|
||||
$this->assertEqual($french_node_path, '/node/' . $english_node_french_translation->id(), 'Normal path works.');
|
||||
// Second call should return the same path.
|
||||
$french_node_path = $this->container->get('path.alias_manager')->getPathByAlias('/' . $french_alias, 'fr');
|
||||
$this->assertEqual($french_node_path, '/node/' . $english_node_french_translation->id(), 'Normal path is the same.');
|
||||
|
||||
// Confirm that the alias works.
|
||||
$french_node_alias = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $english_node_french_translation->id(), 'fr');
|
||||
$this->assertEqual($french_node_alias, '/' . $french_alias, 'Alias works.');
|
||||
// Second call should return the same alias.
|
||||
$french_node_alias = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $english_node_french_translation->id(), 'fr');
|
||||
$this->assertEqual($french_node_alias, '/' . $french_alias, 'Alias is the same.');
|
||||
|
||||
// Confirm that the alias is removed if the translation is deleted.
|
||||
$english_node->removeTranslation('fr');
|
||||
$english_node->save();
|
||||
$this->assertFalse($this->container->get('path.alias_storage')->aliasExists('/' . $french_alias, 'fr'), 'Alias for French translation is removed when translation is deleted.');
|
||||
|
||||
// Check that the English alias still works.
|
||||
$this->drupalGet($english_alias);
|
||||
$this->assertTrue($this->container->get('path.alias_storage')->aliasExists('/' . $english_alias, 'en'), 'English alias is not deleted when French translation is removed.');
|
||||
$this->assertText($english_node->body->value, 'English alias still works');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
/**
|
||||
* Confirm that the Path module user interface works with languages.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathLanguageUiTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['path', 'locale', 'locale_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in user.
|
||||
$web_user = $this->drupalCreateUser(['edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'access administration pages']);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Enable French language.
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => 1];
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a language-neutral URL alias works.
|
||||
*/
|
||||
public function testLanguageNeutralUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = [];
|
||||
$edit['source'] = '/admin/config/search/path';
|
||||
$edit['alias'] = '/' . $name;
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$this->drupalGet($name);
|
||||
$this->assertText(t('Filter aliases'), 'Language-neutral URL alias works');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a default language URL alias works.
|
||||
*/
|
||||
public function testDefaultLanguageUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = [];
|
||||
$edit['source'] = '/admin/config/search/path';
|
||||
$edit['alias'] = '/' . $name;
|
||||
$edit['langcode'] = 'en';
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$this->drupalGet($name);
|
||||
$this->assertText(t('Filter aliases'), 'English URL alias works');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a non-default language URL alias works.
|
||||
*/
|
||||
public function testNonDefaultUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = [];
|
||||
$edit['source'] = '/admin/config/search/path';
|
||||
$edit['alias'] = '/' . $name;
|
||||
$edit['langcode'] = 'fr';
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$this->drupalGet('fr/' . $name);
|
||||
$this->assertText(t('Filter aliases'), 'Foreign URL alias works');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
/**
|
||||
* Tests the Path Node form UI.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathNodeFormTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'path'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(['create page content', 'create url aliases']);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the node form ui.
|
||||
*/
|
||||
public function testNodeForm() {
|
||||
$this->drupalGet('node/add/page');
|
||||
|
||||
// Make sure we have a Path fieldset and Path fields.
|
||||
$this->assertRaw(' id="edit-path-settings"', 'Path settings details exists');
|
||||
$this->assertFieldByName('path[0][alias]', NULL, 'Path alias field exists');
|
||||
|
||||
// Disable the Path field for this content type.
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->removeComponent('path')
|
||||
->save();
|
||||
|
||||
$this->drupalGet('node/add/page');
|
||||
|
||||
// See if the whole fieldset is gone now.
|
||||
$this->assertNoRaw(' id="edit-path-settings"', 'Path settings details does not exist');
|
||||
$this->assertNoFieldByName('path[0][alias]', NULL, 'Path alias field does not exist');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests URL aliases for taxonomy terms.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathTaxonomyTermTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['taxonomy'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a Tags vocabulary for the Article node type.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => t('Tags'),
|
||||
'vid' => 'tags',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
// Create and log in user.
|
||||
$web_user = $this->drupalCreateUser(['administer url aliases', 'administer taxonomy', 'access administration pages']);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alias functionality through the admin interfaces.
|
||||
*/
|
||||
public function testTermAlias() {
|
||||
// Create a term in the default 'Tags' vocabulary with URL alias.
|
||||
$vocabulary = Vocabulary::load('tags');
|
||||
$description = $this->randomMachineName();
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
'description[0][value]' => $description,
|
||||
'path[0][alias]' => '/' . $this->randomMachineName(),
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add', $edit, t('Save'));
|
||||
$tid = db_query("SELECT tid FROM {taxonomy_term_field_data} WHERE name = :name AND default_langcode = 1", [':name' => $edit['name[0][value]']])->fetchField();
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($edit['path[0][alias]']);
|
||||
$this->assertText($description, 'Term can be accessed on URL alias.');
|
||||
|
||||
// Confirm the 'canonical' and 'shortlink' URLs.
|
||||
$elements = $this->xpath("//link[contains(@rel, 'canonical') and contains(@href, '" . $edit['path[0][alias]'] . "')]");
|
||||
$this->assertTrue(!empty($elements), 'Term page contains canonical link URL.');
|
||||
$elements = $this->xpath("//link[contains(@rel, 'shortlink') and contains(@href, 'taxonomy/term/" . $tid . "')]");
|
||||
$this->assertTrue(!empty($elements), 'Term page contains shortlink URL.');
|
||||
|
||||
// Change the term's URL alias.
|
||||
$edit2 = [];
|
||||
$edit2['path[0][alias]'] = '/' . $this->randomMachineName();
|
||||
$this->drupalPostForm('taxonomy/term/' . $tid . '/edit', $edit2, t('Save'));
|
||||
|
||||
// Confirm that the changed alias works.
|
||||
$this->drupalGet(trim($edit2['path[0][alias]'], '/'));
|
||||
$this->assertText($description, 'Term can be accessed on changed URL alias.');
|
||||
|
||||
// Confirm that the old alias no longer works.
|
||||
$this->drupalGet(trim($edit['path[0][alias]'], '/'));
|
||||
$this->assertNoText($description, 'Old URL alias has been removed after altering.');
|
||||
$this->assertResponse(404, 'Old URL alias returns 404.');
|
||||
|
||||
// Remove the term's URL alias.
|
||||
$edit3 = [];
|
||||
$edit3['path[0][alias]'] = '';
|
||||
$this->drupalPostForm('taxonomy/term/' . $tid . '/edit', $edit3, t('Save'));
|
||||
|
||||
// Confirm that the alias no longer works.
|
||||
$this->drupalGet(trim($edit2['path[0][alias]'], '/'));
|
||||
$this->assertNoText($description, 'Old URL alias has been removed after altering.');
|
||||
$this->assertResponse(404, 'Old URL alias returns 404.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Provides a base class for testing the Path module.
|
||||
*/
|
||||
abstract class PathTestBase extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'path'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create Basic page and Article node types.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,20 +16,32 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('path');
|
||||
public static $modules = ['language', 'content_translation', 'path', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d6_url_alias');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig(['node']);
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->migrateUsers(FALSE);
|
||||
$this->migrateFields();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_node_settings',
|
||||
'd6_node',
|
||||
'd6_node_translation',
|
||||
'd6_url_alias',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a path.
|
||||
*
|
||||
* @param string pid
|
||||
* @param string $pid
|
||||
* The path id.
|
||||
* @param array $conditions
|
||||
* The path conditions.
|
||||
@@ -49,48 +61,77 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
|
||||
public function testUrlAlias() {
|
||||
$id_map = $this->getMigration('d6_url_alias')->getIdMap();
|
||||
// Test that the field exists.
|
||||
$conditions = array(
|
||||
$conditions = [
|
||||
'source' => '/node/1',
|
||||
'alias' => '/alias-one',
|
||||
'langcode' => 'af',
|
||||
);
|
||||
];
|
||||
$path = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
$this->assertPath('1', $conditions, $path);
|
||||
$this->assertIdentical($id_map->lookupDestinationID(array($path['pid'])), array('1'), "Test IdMap");
|
||||
$this->assertIdentical($id_map->lookupDestinationID([$path['pid']]), ['1'], "Test IdMap");
|
||||
|
||||
$conditions = array(
|
||||
$conditions = [
|
||||
'source' => '/node/2',
|
||||
'alias' => '/alias-two',
|
||||
'langcode' => 'en',
|
||||
);
|
||||
];
|
||||
$path = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
$this->assertPath('2', $conditions, $path);
|
||||
|
||||
// Test that we can re-import using the UrlAlias destination.
|
||||
Database::getConnection('default', 'migrate')
|
||||
->update('url_alias')
|
||||
->fields(array('dst' => 'new-url-alias'))
|
||||
->fields(['dst' => 'new-url-alias'])
|
||||
->condition('src', 'node/2')
|
||||
->execute();
|
||||
|
||||
\Drupal::database()
|
||||
->update($id_map->mapTableName())
|
||||
->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE))
|
||||
->fields(['source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE])
|
||||
->execute();
|
||||
$migration = $this->getMigration('d6_url_alias');
|
||||
$this->executeMigration($migration);
|
||||
|
||||
$path = \Drupal::service('path.alias_storage')->load(array('pid' => $path['pid']));
|
||||
$path = \Drupal::service('path.alias_storage')->load(['pid' => $path['pid']]);
|
||||
$conditions['alias'] = '/new-url-alias';
|
||||
$this->assertPath('2', $conditions, $path);
|
||||
|
||||
$conditions = array(
|
||||
$conditions = [
|
||||
'source' => '/node/3',
|
||||
'alias' => '/alias-three',
|
||||
'langcode' => 'und',
|
||||
);
|
||||
];
|
||||
$path = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
$this->assertPath('3', $conditions, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the URL alias migration with translated nodes.
|
||||
*/
|
||||
public function testUrlAliasWithTranslatedNodes() {
|
||||
$alias_storage = $this->container->get('path.alias_storage');
|
||||
|
||||
// Alias for the 'The Real McCoy' node in English.
|
||||
$path = $alias_storage->load(['alias' => '/the-real-mccoy']);
|
||||
$this->assertSame('/node/10', $path['source']);
|
||||
$this->assertSame('en', $path['langcode']);
|
||||
|
||||
// Alias for the 'The Real McCoy' French translation,
|
||||
// which should now point to node/10 instead of node/11.
|
||||
$path = $alias_storage->load(['alias' => '/le-vrai-mccoy']);
|
||||
$this->assertSame('/node/10', $path['source']);
|
||||
$this->assertSame('fr', $path['langcode']);
|
||||
|
||||
// Alias for the 'Abantu zulu' node in Zulu.
|
||||
$path = $alias_storage->load(['alias' => '/abantu-zulu']);
|
||||
$this->assertSame('/node/12', $path['source']);
|
||||
$this->assertSame('zu', $path['langcode']);
|
||||
|
||||
// Alias for the 'Abantu zulu' English translation,
|
||||
// which should now point to node/12 instead of node/13.
|
||||
$path = $alias_storage->load(['alias' => '/the-zulu-people']);
|
||||
$this->assertSame('/node/12', $path['source']);
|
||||
$this->assertSame('en', $path['langcode']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,14 +14,34 @@ class MigrateUrlAliasTest extends MigrateDrupal7TestBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['path'];
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'path',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d7_url_alias');
|
||||
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig('node');
|
||||
$this->installSchema('node', ['node_access']);
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_user_role',
|
||||
'd7_user',
|
||||
'd7_node_type',
|
||||
'd7_node',
|
||||
'd7_node_translation',
|
||||
'd7_url_alias',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,4 +58,33 @@ class MigrateUrlAliasTest extends MigrateDrupal7TestBase {
|
||||
$this->assertIdentical('und', $path['langcode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the URL alias migration with translated nodes.
|
||||
*/
|
||||
public function testUrlAliasWithTranslatedNodes() {
|
||||
$alias_storage = $this->container->get('path.alias_storage');
|
||||
|
||||
// Alias for the 'The thing about Deep Space 9' node in English.
|
||||
$path = $alias_storage->load(['alias' => '/deep-space-9']);
|
||||
$this->assertSame('/node/2', $path['source']);
|
||||
$this->assertSame('en', $path['langcode']);
|
||||
|
||||
// Alias for the 'The thing about Deep Space 9' Icelandic translation,
|
||||
// which should now point to node/2 instead of node/3.
|
||||
$path = $alias_storage->load(['alias' => '/deep-space-9-is']);
|
||||
$this->assertSame('/node/2', $path['source']);
|
||||
$this->assertSame('is', $path['langcode']);
|
||||
|
||||
// Alias for the 'The thing about Firefly' node in Icelandic.
|
||||
$path = $alias_storage->load(['alias' => '/firefly-is']);
|
||||
$this->assertSame('/node/4', $path['source']);
|
||||
$this->assertSame('is', $path['langcode']);
|
||||
|
||||
// Alias for the 'The thing about Firefly' English translation,
|
||||
// which should now point to node/4 instead of node/5.
|
||||
$path = $alias_storage->load(['alias' => '/firefly']);
|
||||
$this->assertSame('/node/4', $path['source']);
|
||||
$this->assertSame('en', $path['langcode']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class PathNoCanonicalLinkTest extends KernelTestBase {
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('path', 'content_translation_test', 'language', 'entity_test', 'user', 'system');
|
||||
public static $modules = ['path', 'content_translation_test', 'language', 'entity_test', 'user', 'system'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests the d6_url_alias source plugin.
|
||||
*
|
||||
* @covers \Drupal\path\Plugin\migrate\source\d6\UrlAlias
|
||||
* @group path
|
||||
*/
|
||||
class UrlAliasTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate_drupal', 'path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['url_alias'] = [
|
||||
[
|
||||
'pid' => 1,
|
||||
'src' => 'node/1',
|
||||
'dst' => 'test-article',
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'pid' => 2,
|
||||
'src' => 'node/2',
|
||||
'dst' => 'another-alias',
|
||||
'language' => 'en',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = $tests[0]['source_data']['url_alias'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests the d7_url_alias source plugin.
|
||||
*
|
||||
* @covers \Drupal\path\Plugin\migrate\source\d7\UrlAlias
|
||||
* @group path
|
||||
*/
|
||||
class UrlAliasTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate_drupal', 'path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['url_alias'] = [
|
||||
[
|
||||
'pid' => 1,
|
||||
'source' => 'node/1',
|
||||
'alias' => 'test-article',
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'pid' => 2,
|
||||
'source' => 'node/2',
|
||||
'alias' => 'another-alias',
|
||||
'language' => 'en',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = $tests[0]['source_data']['url_alias'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class PathFieldDefinitionTest extends BaseFieldDefinitionTestBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getModuleAndPath() {
|
||||
return array('path', dirname(dirname(dirname(dirname(__DIR__)))));
|
||||
return ['path', dirname(dirname(dirname(dirname(__DIR__))))];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ class PathFieldDefinitionTest extends BaseFieldDefinitionTestBase {
|
||||
* @covers ::getSchema
|
||||
*/
|
||||
public function testGetColumns() {
|
||||
$this->assertSame(array(), $this->definition->getColumns());
|
||||
$this->assertSame([], $this->definition->getColumns());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user