Move into nested docroot
This commit is contained in:
parent
83a0d3a149
commit
c8b70abde9
13405 changed files with 0 additions and 0 deletions
5
web/core/modules/path/config/schema/path.schema.yml
Normal file
5
web/core/modules/path/config/schema/path.schema.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Schema for the configuration files of the Path module.
|
||||
|
||||
field.widget.settings.path:
|
||||
type: mapping
|
||||
label: 'Link format settings'
|
36
web/core/modules/path/migration_templates/d6_url_alias.yml
Normal file
36
web/core/modules/path/migration_templates/d6_url_alias.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
id: d6_url_alias
|
||||
label: URL aliases
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: d6_url_alias
|
||||
constants:
|
||||
slash: '/'
|
||||
process:
|
||||
source:
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/slash
|
||||
- src
|
||||
alias:
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/slash
|
||||
- dst
|
||||
langcode:
|
||||
plugin: d6_url_alias_language
|
||||
source: language
|
||||
node_translation:
|
||||
-
|
||||
plugin: explode
|
||||
source: src
|
||||
delimiter: /
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
-
|
||||
plugin: migration
|
||||
migration: d6_node_translation
|
||||
destination:
|
||||
plugin: url_alias
|
22
web/core/modules/path/migration_templates/d7_url_alias.yml
Normal file
22
web/core/modules/path/migration_templates/d7_url_alias.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
id: d7_url_alias
|
||||
label: URL aliases
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: d7_url_alias
|
||||
constants:
|
||||
slash: '/'
|
||||
process:
|
||||
source:
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/slash
|
||||
- source
|
||||
alias:
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/slash
|
||||
- alias
|
||||
langcode: language
|
||||
destination:
|
||||
plugin: url_alias
|
66
web/core/modules/path/path.api.php
Normal file
66
web/core/modules/path/path.api.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Path module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Respond to a path being inserted.
|
||||
*
|
||||
* @param array $path
|
||||
* The array structure is identical to that of the return value of
|
||||
* \Drupal\Core\Path\PathInterface::save().
|
||||
*
|
||||
* @see \Drupal\Core\Path\PathInterface::save()
|
||||
*/
|
||||
function hook_path_insert($path) {
|
||||
db_insert('mytable')
|
||||
->fields(array(
|
||||
'alias' => $path['alias'],
|
||||
'pid' => $path['pid'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to a path being updated.
|
||||
*
|
||||
* @param array $path
|
||||
* The array structure is identical to that of the return value of
|
||||
* \Drupal\Core\Path\PathInterface::save().
|
||||
*
|
||||
* @see \Drupal\Core\Path\PathInterface::save()
|
||||
*/
|
||||
function hook_path_update($path) {
|
||||
if ($path['alias'] != $path['original']['alias']) {
|
||||
db_update('mytable')
|
||||
->fields(array('alias' => $path['alias']))
|
||||
->condition('pid', $path['pid'])
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to a path being deleted.
|
||||
*
|
||||
* @param array $path
|
||||
* The array structure is identical to that of the return value of
|
||||
* \Drupal\Core\Path\PathInterface::save().
|
||||
*
|
||||
* @see \Drupal\Core\Path\PathInterface::delete()
|
||||
*/
|
||||
function hook_path_delete($path) {
|
||||
db_delete('mytable')
|
||||
->condition('pid', $path['pid'])
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
7
web/core/modules/path/path.info.yml
Normal file
7
web/core/modules/path/path.info.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
name: Path
|
||||
type: module
|
||||
description: 'Allows users to rename URLs.'
|
||||
package: Core
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
configure: path.admin_overview
|
32
web/core/modules/path/path.install
Normal file
32
web/core/modules/path/path.install
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Update functions for the path module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup updates-8.2.0
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-8.2.0".
|
||||
*/
|
29
web/core/modules/path/path.js
Normal file
29
web/core/modules/path/path.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* @file
|
||||
* Attaches behaviors for the Path module.
|
||||
*/
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Behaviors for settings summaries on path edit forms.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches summary behavior on path edit forms.
|
||||
*/
|
||||
Drupal.behaviors.pathDetailsSummaries = {
|
||||
attach: function (context) {
|
||||
$(context).find('.path-form').drupalSetSummary(function (context) {
|
||||
var path = $('.js-form-item-path-0-alias input').val();
|
||||
|
||||
return path ?
|
||||
Drupal.t('Alias: @alias', {'@alias': path}) :
|
||||
Drupal.t('No alias');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
8
web/core/modules/path/path.libraries.yml
Normal file
8
web/core/modules/path/path.libraries.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
drupal.path:
|
||||
version: VERSION
|
||||
js:
|
||||
path.js: {}
|
||||
dependencies:
|
||||
- core/jquery
|
||||
- core/drupal
|
||||
- core/drupal.form
|
5
web/core/modules/path/path.links.action.yml
Normal file
5
web/core/modules/path/path.links.action.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
path.admin_add:
|
||||
route_name: path.admin_add
|
||||
title: 'Add alias'
|
||||
appears_on:
|
||||
- path.admin_overview
|
6
web/core/modules/path/path.links.menu.yml
Normal file
6
web/core/modules/path/path.links.menu.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
path.admin_overview:
|
||||
title: 'URL aliases'
|
||||
description: 'Add custom URLs to existing paths.'
|
||||
route_name: path.admin_overview
|
||||
parent: system.admin_config_search
|
||||
weight: -5
|
4
web/core/modules/path/path.links.task.yml
Normal file
4
web/core/modules/path/path.links.task.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
path.admin_overview:
|
||||
title: List
|
||||
route_name: path.admin_overview
|
||||
base_route: path.admin_overview
|
78
web/core/modules/path/path.module
Normal file
78
web/core/modules/path/path.module
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Enables users to rename URLs.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function path_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
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 .= '<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 .= '<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 .= '</dl>';
|
||||
return $output;
|
||||
|
||||
case 'path.admin_overview':
|
||||
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>';
|
||||
|
||||
case 'path.admin_add':
|
||||
return '<p>' . t('Enter the path you wish to create the alias for, followed by the name of the new alias.') . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
|
||||
*/
|
||||
function path_form_node_form_alter(&$form, FormStateInterface $form_state) {
|
||||
$node = $form_state->getFormObject()->getEntity();
|
||||
$form['path_settings'] = array(
|
||||
'#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'),
|
||||
),
|
||||
'#weight' => 30,
|
||||
);
|
||||
$form['path']['#group'] = 'path_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_base_field_info().
|
||||
*/
|
||||
function path_entity_base_field_info(EntityTypeInterface $entity_type) {
|
||||
if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') {
|
||||
$fields['path'] = BaseFieldDefinition::create('path')
|
||||
->setLabel(t('URL alias'))
|
||||
->setTranslatable(TRUE)
|
||||
->setDisplayOptions('form', array(
|
||||
'type' => 'path',
|
||||
'weight' => 30,
|
||||
))
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setComputed(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
4
web/core/modules/path/path.permissions.yml
Normal file
4
web/core/modules/path/path.permissions.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
administer url aliases:
|
||||
title: 'Administer URL aliases'
|
||||
create url aliases:
|
||||
title: 'Create and edit URL aliases'
|
40
web/core/modules/path/path.routing.yml
Normal file
40
web/core/modules/path/path.routing.yml
Normal file
|
@ -0,0 +1,40 @@
|
|||
path.delete:
|
||||
path: '/admin/config/search/path/delete/{pid}'
|
||||
defaults:
|
||||
_form: '\Drupal\path\Form\DeleteForm'
|
||||
_title: 'Delete alias'
|
||||
requirements:
|
||||
_permission: 'administer url aliases'
|
||||
|
||||
path.admin_overview:
|
||||
path: '/admin/config/search/path'
|
||||
defaults:
|
||||
_title: 'URL aliases'
|
||||
_controller: '\Drupal\path\Controller\PathController::adminOverview'
|
||||
keys: NULL
|
||||
requirements:
|
||||
_permission: 'administer url aliases'
|
||||
|
||||
path.admin_overview_filter:
|
||||
path: '/admin/config/search/path/filter'
|
||||
defaults:
|
||||
_title: 'URL aliases'
|
||||
_controller: '\Drupal\path\Controller\PathController::adminOverview'
|
||||
requirements:
|
||||
_permission: 'administer url aliases'
|
||||
|
||||
path.admin_add:
|
||||
path: '/admin/config/search/path/add'
|
||||
defaults:
|
||||
_title: 'Add alias'
|
||||
_form: '\Drupal\path\Form\AddForm'
|
||||
requirements:
|
||||
_permission: 'administer url aliases'
|
||||
|
||||
path.admin_edit:
|
||||
path: '/admin/config/search/path/edit/{pid}'
|
||||
defaults:
|
||||
_title: 'Edit alias'
|
||||
_form: '\Drupal\path\Form\EditForm'
|
||||
requirements:
|
||||
_permission: 'administer url aliases'
|
133
web/core/modules/path/src/Controller/PathController.php
Normal file
133
web/core/modules/path/src/Controller/PathController.php
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Path\AliasStorageInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Controller routines for path routes.
|
||||
*/
|
||||
class PathController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The path alias storage.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasStorageInterface
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* The path alias manager.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasManagerInterface
|
||||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* Constructs a new PathController.
|
||||
*
|
||||
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage
|
||||
* The path alias storage.
|
||||
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
|
||||
* The path alias manager.
|
||||
*/
|
||||
public function __construct(AliasStorageInterface $alias_storage, AliasManagerInterface $alias_manager) {
|
||||
$this->aliasStorage = $alias_storage;
|
||||
$this->aliasManager = $alias_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('path.alias_storage'),
|
||||
$container->get('path.alias_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the path administration overview page.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by drupal_render().
|
||||
*/
|
||||
public function adminOverview(Request $request) {
|
||||
$keys = $request->query->get('search');
|
||||
// Add the filter form above the overview table.
|
||||
$build['path_admin_filter_form'] = $this->formBuilder()->getForm('Drupal\path\Form\PathFilterForm', $keys);
|
||||
// Enable language column if language.module is enabled or if we have any
|
||||
// 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');
|
||||
if ($multilanguage) {
|
||||
$header[] = array('data' => $this->t('Language'), 'field' => 'langcode');
|
||||
}
|
||||
$header[] = $this->t('Operations');
|
||||
|
||||
$rows = array();
|
||||
$destination = $this->getDestinationArray();
|
||||
foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) {
|
||||
$row = array();
|
||||
// @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(
|
||||
'alias' => TRUE,
|
||||
'attributes' => array('title' => $data->source),
|
||||
)));
|
||||
if ($multilanguage) {
|
||||
$row['data']['language_name'] = $this->languageManager()->getLanguageName($data->langcode);
|
||||
}
|
||||
|
||||
$operations = array();
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => Url::fromRoute('path.admin_edit', ['pid' => $data->pid], ['query' => $destination]),
|
||||
);
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => Url::fromRoute('path.delete', ['pid' => $data->pid], ['query' => $destination]),
|
||||
);
|
||||
$row['data']['operations'] = array(
|
||||
'data' => array(
|
||||
'#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');
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['path_table'] = array(
|
||||
'#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');
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
31
web/core/modules/path/src/Form/AddForm.php
Normal file
31
web/core/modules/path/src/Form/AddForm.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Provides the path add form.
|
||||
*/
|
||||
class AddForm extends PathFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'path_admin_add';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildPath($pid) {
|
||||
return array(
|
||||
'source' => '',
|
||||
'alias' => '',
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'pid' => NULL,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
90
web/core/modules/path/src/Form/DeleteForm.php
Normal file
90
web/core/modules/path/src/Form/DeleteForm.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\AliasStorageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Builds the form to delete a path alias.
|
||||
*/
|
||||
class DeleteForm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The alias storage service.
|
||||
*
|
||||
* @var AliasStorageInterface $path
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* The path alias being deleted.
|
||||
*
|
||||
* @var array $pathAlias
|
||||
*/
|
||||
protected $pathAlias;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\path\Form\DeleteForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage
|
||||
* The alias storage service.
|
||||
*/
|
||||
public function __construct(AliasStorageInterface $alias_storage) {
|
||||
$this->aliasStorage = $alias_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('path.alias_storage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'path_alias_delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return t('Are you sure you want to delete path alias %title?', array('%title' => $this->pathAlias['alias']));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('path.admin_overview');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
|
||||
$this->pathAlias = $this->aliasStorage->load(array('pid' => $pid));
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->aliasStorage->delete(array('pid' => $this->pathAlias['pid']));
|
||||
|
||||
$form_state->setRedirect('path.admin_overview');
|
||||
}
|
||||
|
||||
}
|
59
web/core/modules/path/src/Form/EditForm.php
Normal file
59
web/core/modules/path/src/Form/EditForm.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides the path edit form.
|
||||
*/
|
||||
class EditForm extends PathFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'path_admin_edit';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildPath($pid) {
|
||||
return $this->aliasStorage->load(array('pid' => $pid));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
|
||||
$form = parent::buildForm($form, $form_state, $pid);
|
||||
|
||||
$form['#title'] = $this->path['alias'];
|
||||
$form['pid'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $this->path['pid'],
|
||||
);
|
||||
|
||||
$url = new Url('path.delete', array(
|
||||
'pid' => $this->path['pid'],
|
||||
));
|
||||
|
||||
if ($this->getRequest()->query->has('destination')) {
|
||||
$url->setOption('query', $this->getDestinationArray());
|
||||
}
|
||||
|
||||
$form['actions']['delete'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Delete'),
|
||||
'#url' => $url,
|
||||
'#attributes' => array(
|
||||
'class' => array('button', 'button--danger'),
|
||||
),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
69
web/core/modules/path/src/Form/PathFilterForm.php
Normal file
69
web/core/modules/path/src/Form/PathFilterForm.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides the path admin overview filter form.
|
||||
*/
|
||||
class PathFilterForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'path_admin_filter_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $keys = NULL) {
|
||||
$form['#attributes'] = array('class' => array('search-form'));
|
||||
$form['basic'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Filter aliases'),
|
||||
'#open' => TRUE,
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
);
|
||||
$form['basic']['filter'] = array(
|
||||
'#type' => 'search',
|
||||
'#title' => 'Path alias',
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $keys,
|
||||
'#maxlength' => 128,
|
||||
'#size' => 25,
|
||||
);
|
||||
$form['basic']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Filter'),
|
||||
);
|
||||
if ($keys) {
|
||||
$form['basic']['reset'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Reset'),
|
||||
'#submit' => array('::resetForm'),
|
||||
);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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'))),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the filter selections.
|
||||
*/
|
||||
public function resetForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirect('path.admin_overview');
|
||||
}
|
||||
|
||||
}
|
220
web/core/modules/path/src/Form/PathFormBase.php
Normal file
220
web/core/modules/path/src/Form/PathFormBase.php
Normal file
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Path\AliasStorageInterface;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\Core\Routing\RequestContext;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a base class for path add/edit forms.
|
||||
*/
|
||||
abstract class PathFormBase extends FormBase {
|
||||
|
||||
/**
|
||||
* An array containing the path ID, source, alias, and language code.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* The path alias storage.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasStorageInterface
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* The path alias manager.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasManagerInterface
|
||||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* The path validator.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathValidatorInterface
|
||||
*/
|
||||
protected $pathValidator;
|
||||
|
||||
/**
|
||||
* The request context.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RequestContext
|
||||
*/
|
||||
protected $requestContext;
|
||||
|
||||
/**
|
||||
* Constructs a new PathController.
|
||||
*
|
||||
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage
|
||||
* The path alias storage.
|
||||
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
|
||||
* The path alias manager.
|
||||
* @param \Drupal\Core\Path\PathValidatorInterface $path_validator
|
||||
* The path validator.
|
||||
* @param \Drupal\Core\Routing\RequestContext $request_context
|
||||
* The request context.
|
||||
*/
|
||||
public function __construct(AliasStorageInterface $alias_storage, AliasManagerInterface $alias_manager, PathValidatorInterface $path_validator, RequestContext $request_context) {
|
||||
$this->aliasStorage = $alias_storage;
|
||||
$this->aliasManager = $alias_manager;
|
||||
$this->pathValidator = $path_validator;
|
||||
$this->requestContext = $request_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('path.alias_storage'),
|
||||
$container->get('path.alias_manager'),
|
||||
$container->get('path.validator'),
|
||||
$container->get('router.request_context')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the path used by the form.
|
||||
*
|
||||
* @param int|null $pid
|
||||
* Either the unique path ID, or NULL if a new one is being created.
|
||||
*/
|
||||
abstract protected function buildPath($pid);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
|
||||
$this->path = $this->buildPath($pid);
|
||||
$form['source'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Existing system path'),
|
||||
'#default_value' => $this->path['source'],
|
||||
'#maxlength' => 255,
|
||||
'#size' => 45,
|
||||
'#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(
|
||||
'#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.'),
|
||||
'#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();
|
||||
foreach ($languages as $langcode => $language) {
|
||||
$language_options[$langcode] = $language->getName();
|
||||
}
|
||||
|
||||
$form['langcode'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Language'),
|
||||
'#options' => $language_options,
|
||||
'#empty_value' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'#empty_option' => $this->t('- None -'),
|
||||
'#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(
|
||||
'#type' => 'value',
|
||||
'#value' => $this->path['langcode']
|
||||
);
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$source = &$form_state->getValue('source');
|
||||
$source = $this->aliasManager->getPathByAlias($source);
|
||||
$alias = &$form_state->getValue('alias');
|
||||
|
||||
// Trim the submitted value of whitespace and slashes. Ensure to not trim
|
||||
// the slash on the left side.
|
||||
$alias = rtrim(trim(trim($alias), ''), "\\/");
|
||||
|
||||
if ($source[0] !== '/') {
|
||||
$form_state->setErrorByName('source', 'The source path has to start with a slash.');
|
||||
}
|
||||
if ($alias[0] !== '/') {
|
||||
$form_state->setErrorByName('alias', 'The alias path has to start with a slash.');
|
||||
}
|
||||
|
||||
// Language is only set if language.module is enabled, otherwise save for all
|
||||
// languages.
|
||||
$langcode = $form_state->getValue('langcode', LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
if ($this->aliasStorage->aliasExists($alias, $langcode, $this->path['source'])) {
|
||||
$stored_alias = $this->aliasStorage->load(['alias' => $alias, 'langcode' => $langcode]);
|
||||
if ($stored_alias['alias'] !== $alias) {
|
||||
// The alias already exists with different capitalization as the default
|
||||
// implementation of AliasStorageInterface::aliasExists is
|
||||
// case-insensitive.
|
||||
$form_state->setErrorByName('alias', t('The alias %alias could not be added because it is already in use in this language with different capitalization: %stored_alias.', [
|
||||
'%alias' => $alias,
|
||||
'%stored_alias' => $stored_alias['alias'],
|
||||
]));
|
||||
}
|
||||
else {
|
||||
$form_state->setErrorByName('alias', t('The alias %alias is already in use in this language.', ['%alias' => $alias]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Remove unnecessary values.
|
||||
$form_state->cleanValues();
|
||||
|
||||
$pid = $form_state->getValue('pid', 0);
|
||||
$source = $form_state->getValue('source');
|
||||
$alias = $form_state->getValue('alias');
|
||||
// Language is only set if language.module is enabled, otherwise save for all
|
||||
// languages.
|
||||
$langcode = $form_state->getValue('langcode', LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
$this->aliasStorage->save($source, $alias, $langcode, $pid);
|
||||
|
||||
drupal_set_message($this->t('The alias has been saved.'));
|
||||
$form_state->setRedirect('path.admin_overview');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Field\FieldItemList;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Represents a configurable entity path field.
|
||||
*/
|
||||
class PathFieldItemList extends FieldItemList {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
|
||||
if ($operation == 'view') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Component\Utility\Random;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemBase;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
|
||||
/**
|
||||
* Defines the 'path' entity field type.
|
||||
*
|
||||
* @FieldType(
|
||||
* id = "path",
|
||||
* label = @Translation("Path"),
|
||||
* description = @Translation("An entity field containing a path alias and related data."),
|
||||
* no_ui = TRUE,
|
||||
* default_widget = "path",
|
||||
* list_class = "\Drupal\path\Plugin\Field\FieldType\PathFieldItemList"
|
||||
* )
|
||||
*/
|
||||
class PathItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['alias'] = DataDefinition::create('string')
|
||||
->setLabel(t('Path alias'));
|
||||
$properties['pid'] = DataDefinition::create('integer')
|
||||
->setLabel(t('Path id'));
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave() {
|
||||
$this->alias = trim($this->alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave($update) {
|
||||
if (!$update) {
|
||||
if ($this->alias) {
|
||||
$entity = $this->getEntity();
|
||||
if ($path = \Drupal::service('path.alias_storage')->save('/' . $entity->urlInfo()->getInternalPath(), $this->alias, $this->getLangcode())) {
|
||||
$this->pid = $path['pid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Delete old alias if user erased it.
|
||||
if ($this->pid && !$this->alias) {
|
||||
\Drupal::service('path.alias_storage')->delete(array('pid' => $this->pid));
|
||||
}
|
||||
// Only save a non-empty alias.
|
||||
elseif ($this->alias) {
|
||||
$entity = $this->getEntity();
|
||||
\Drupal::service('path.alias_storage')->save('/' . $entity->urlInfo()->getInternalPath(), $this->alias, $this->getLangcode(), $this->pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
|
||||
$random = new Random();
|
||||
$values['alias'] = str_replace(' ', '-', strtolower($random->sentences(3)));
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function mainPropertyName() {
|
||||
return 'alias';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\Field\FieldWidget;
|
||||
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\WidgetBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'path' widget.
|
||||
*
|
||||
* @FieldWidget(
|
||||
* id = "path",
|
||||
* label = @Translation("URL alias"),
|
||||
* field_types = {
|
||||
* "path"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class PathWidget extends WidgetBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
$entity = $items->getEntity();
|
||||
$path = array();
|
||||
if (!$entity->isNew()) {
|
||||
$conditions = array('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 += array(
|
||||
'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(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $element['#title'],
|
||||
'#default_value' => $path['alias'],
|
||||
'#required' => $element['#required'],
|
||||
'#maxlength' => 255,
|
||||
'#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'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $path['pid'],
|
||||
);
|
||||
$element['source'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $path['source'],
|
||||
);
|
||||
$element['langcode'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $path['langcode'],
|
||||
);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element validation handler for URL alias form element.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The form state.
|
||||
*/
|
||||
public static function validateFormElement(array &$element, FormStateInterface $form_state) {
|
||||
// Trim the submitted value of whitespace and slashes.
|
||||
$alias = rtrim(trim($element['alias']['#value']), " \\/");
|
||||
if (!empty($alias)) {
|
||||
$form_state->setValueForElement($element['alias'], $alias);
|
||||
|
||||
// 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.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($alias && $alias[0] !== '/') {
|
||||
$form_state->setError($element, t('The alias needs to start with a slash.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
|
||||
return $element['alias'];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Path\AliasStorage;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "url_alias"
|
||||
* )
|
||||
*/
|
||||
class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The alias storage service.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasStorage $aliasStorage
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* Constructs an entity destination plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param \Drupal\Core\Path\AliasStorage $alias_storage
|
||||
* The alias storage service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, AliasStorage $alias_storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->aliasStorage = $alias_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('path.alias_storage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$source = $row->getDestinationProperty('source');
|
||||
$alias = $row->getDestinationProperty('alias');
|
||||
$langcode = $row->getDestinationProperty('langcode');
|
||||
$pid = $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')) {
|
||||
|
||||
// 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 array($path['pid']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['pid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
return [
|
||||
'pid' => 'The path id',
|
||||
'source' => 'The source path.',
|
||||
'alias' => 'The URL alias.',
|
||||
'langcode' => 'The language code for the URL.',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Url alias language code process.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_url_alias_language"
|
||||
* )
|
||||
*/
|
||||
class UrlAliasLanguage extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$langcode = ($value === '') ? LanguageInterface::LANGCODE_NOT_SPECIFIED : $value;
|
||||
return $langcode;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Base class for the url_alias source plugins.
|
||||
*/
|
||||
abstract class UrlAliasBase extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// 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(
|
||||
'pid' => $this->t('The numeric identifier of the path alias.'),
|
||||
'language' => $this->t('The language code of the URL alias.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['pid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\path\Plugin\migrate\source\UrlAliasBase;
|
||||
|
||||
/**
|
||||
* URL aliases source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_url_alias",
|
||||
* source_provider = "path"
|
||||
* )
|
||||
*/
|
||||
class UrlAlias extends UrlAliasBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = parent::fields();
|
||||
$fields['src'] = $this->t('The internal system path.');
|
||||
$fields['dst'] = $this->t('The path alias.');
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\path\Plugin\migrate\source\UrlAliasBase;
|
||||
|
||||
/**
|
||||
* URL aliases source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_url_alias",
|
||||
* source_provider = "path"
|
||||
* )
|
||||
*/
|
||||
class UrlAlias extends UrlAliasBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = parent::fields();
|
||||
$fields['source'] = $this->t('The internal system path.');
|
||||
$fields['alias'] = $this->t('The path alias.');
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
100
web/core/modules/path/src/Tests/PathAdminTest.php
Normal file
100
web/core/modules/path/src/Tests/PathAdminTest.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
/**
|
||||
* Tests the Path admin UI.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathAdminTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('path');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(array('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 = array(
|
||||
'source' => '/node/' . $node1->id(),
|
||||
'alias' => $alias1,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$alias2 = '/' . $this->randomMachineName(8);
|
||||
$edit = array(
|
||||
'source' => '/node/' . $node2->id(),
|
||||
'alias' => $alias2,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
$alias3 = '/' . $this->randomMachineName(4) . '/' . $this->randomMachineName(4);
|
||||
$edit = array(
|
||||
'source' => '/node/' . $node3->id(),
|
||||
'alias' => $alias3,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
|
||||
|
||||
// Filter by the first alias.
|
||||
$edit = array(
|
||||
'filter' => $alias1,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertLinkByHref($alias1);
|
||||
$this->assertNoLinkByHref($alias2);
|
||||
$this->assertNoLinkByHref($alias3);
|
||||
|
||||
// Filter by the second alias.
|
||||
$edit = array(
|
||||
'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 = array(
|
||||
'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 = array(
|
||||
'filter' => $this->randomMachineName(10),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Filter'));
|
||||
$this->assertNoLinkByHref($alias1);
|
||||
$this->assertNoLinkByHref($alias2);
|
||||
|
||||
// Reset the filter.
|
||||
$edit = array();
|
||||
$this->drupalPostForm(NULL, $edit, t('Reset'));
|
||||
$this->assertLinkByHref($alias1);
|
||||
$this->assertLinkByHref($alias2);
|
||||
}
|
||||
|
||||
}
|
361
web/core/modules/path/src/Tests/PathAliasTest.php
Normal file
361
web/core/modules/path/src/Tests/PathAliasTest.php
Normal file
|
@ -0,0 +1,361 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
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 = array('path');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'administer url aliases', 'create url aliases'));
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the path cache.
|
||||
*/
|
||||
function testPathCache() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = array();
|
||||
$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'], '/'), array('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.
|
||||
*/
|
||||
function testAdminAlias() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = array();
|
||||
$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.', array('%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?', array('%name' => $edit['alias'])));
|
||||
$this->drupalPostForm(NULL, array(), 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 = array();
|
||||
$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 = array();
|
||||
$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 = array();
|
||||
$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.', array('%alias' => $edit['alias'])));
|
||||
|
||||
// Create an alias without a starting slash.
|
||||
$node5 = $this->drupalCreateNode();
|
||||
|
||||
$edit = array();
|
||||
$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.
|
||||
*/
|
||||
function testNodeAlias() {
|
||||
// Create test node.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
|
||||
// Create alias.
|
||||
$edit = array();
|
||||
$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', array('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 = array('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 = array('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 = array('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.
|
||||
*/
|
||||
function getPID($alias) {
|
||||
return db_query("SELECT pid FROM {url_alias} WHERE alias = :alias", array(':alias' => $alias))->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that duplicate aliases fail validation.
|
||||
*/
|
||||
function testDuplicateNodeAlias() {
|
||||
// Create one node with a random alias.
|
||||
$node_one = $this->drupalCreateNode();
|
||||
$edit = array();
|
||||
$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.');
|
||||
}
|
||||
|
||||
}
|
196
web/core/modules/path/src/Tests/PathLanguageTest.php
Normal file
196
web/core/modules/path/src/Tests/PathLanguageTest.php
Normal file
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
/**
|
||||
* Confirm that paths work with translated nodes.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathLanguageTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('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 = array(
|
||||
'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 = array();
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = array('language_interface[enabled][language-url]' => 1);
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
|
||||
// Enable translation for page node.
|
||||
$edit = array(
|
||||
'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.
|
||||
*/
|
||||
function testAliasTranslation() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$english_node = $this->drupalCreateNode(array('type' => 'page', 'langcode' => 'en'));
|
||||
$english_alias = $this->randomMachineName();
|
||||
|
||||
// Edit the node to set language and path.
|
||||
$edit = array();
|
||||
$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 = array();
|
||||
$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(array($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', array('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 = array(
|
||||
'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 = array('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 = array('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');
|
||||
}
|
||||
|
||||
}
|
81
web/core/modules/path/src/Tests/PathLanguageUiTest.php
Normal file
81
web/core/modules/path/src/Tests/PathLanguageUiTest.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
/**
|
||||
* Confirm that the Path module user interface works with languages.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathLanguageUiTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('path', 'locale', 'locale_test');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in user.
|
||||
$web_user = $this->drupalCreateUser(array('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 = array();
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = array('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.
|
||||
*/
|
||||
function testLanguageNeutralUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = array();
|
||||
$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.
|
||||
*/
|
||||
function testDefaultLanguageUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = array();
|
||||
$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.
|
||||
*/
|
||||
function testNonDefaultUrl() {
|
||||
$name = $this->randomMachineName(8);
|
||||
$edit = array();
|
||||
$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');
|
||||
}
|
||||
|
||||
}
|
49
web/core/modules/path/src/Tests/PathNodeFormTest.php
Normal file
49
web/core/modules/path/src/Tests/PathNodeFormTest.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
/**
|
||||
* Tests the Path Node form UI.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathNodeFormTest extends PathTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'path');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user and log in.
|
||||
$web_user = $this->drupalCreateUser(array('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');
|
||||
}
|
||||
|
||||
}
|
86
web/core/modules/path/src/Tests/PathTaxonomyTermTest.php
Normal file
86
web/core/modules/path/src/Tests/PathTaxonomyTermTest.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
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 = array('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(array('administer url aliases', 'administer taxonomy', 'access administration pages'));
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alias functionality through the admin interfaces.
|
||||
*/
|
||||
function testTermAlias() {
|
||||
// Create a term in the default 'Tags' vocabulary with URL alias.
|
||||
$vocabulary = Vocabulary::load('tags');
|
||||
$description = $this->randomMachineName();
|
||||
$edit = array(
|
||||
'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", array(':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 = array();
|
||||
$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 = array();
|
||||
$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.');
|
||||
}
|
||||
|
||||
}
|
29
web/core/modules/path/src/Tests/PathTestBase.php
Normal file
29
web/core/modules/path/src/Tests/PathTestBase.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Provides a base class for testing the Path module.
|
||||
*/
|
||||
abstract class PathTestBase extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('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'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* URL alias migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$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
|
||||
* The path id.
|
||||
* @param array $conditions
|
||||
* The path conditions.
|
||||
* @param array $path
|
||||
* The path.
|
||||
*/
|
||||
private function assertPath($pid, $conditions, $path) {
|
||||
$this->assertTrue($path, "Path alias for " . $conditions['source'] . " successfully loaded.");
|
||||
$this->assertIdentical($conditions['alias'], $path['alias']);
|
||||
$this->assertIdentical($conditions['langcode'], $path['langcode']);
|
||||
$this->assertIdentical($conditions['source'], $path['source']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the url alias migration.
|
||||
*/
|
||||
public function testUrlAlias() {
|
||||
$id_map = $this->getMigration('d6_url_alias')->getIdMap();
|
||||
// Test that the field exists.
|
||||
$conditions = array(
|
||||
'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");
|
||||
|
||||
$conditions = array(
|
||||
'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'))
|
||||
->condition('src', 'node/2')
|
||||
->execute();
|
||||
|
||||
\Drupal::database()
|
||||
->update($id_map->mapTableName())
|
||||
->fields(array('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']));
|
||||
$conditions['alias'] = '/new-url-alias';
|
||||
$this->assertPath('2', $conditions, $path);
|
||||
|
||||
$conditions = array(
|
||||
'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']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests URL alias migration.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class MigrateUrlAliasTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d7_url_alias');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the URL alias migration.
|
||||
*/
|
||||
public function testUrlAlias() {
|
||||
$path = \Drupal::service('path.alias_storage')->load([
|
||||
'source' => '/taxonomy/term/4',
|
||||
'alias' => '/term33',
|
||||
'langcode' => 'und',
|
||||
]);
|
||||
$this->assertIdentical('/taxonomy/term/4', $path['source']);
|
||||
$this->assertIdentical('/term33', $path['alias']);
|
||||
$this->assertIdentical('und', $path['langcode']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Kernel;
|
||||
|
||||
use Drupal\content_translation_test\Entity\EntityTestTranslatableUISkip;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests path alias deletion when there is no canonical link template.
|
||||
*
|
||||
* @group path
|
||||
*/
|
||||
class PathNoCanonicalLinkTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('path', 'content_translation_test', 'language', 'entity_test', 'user', 'system');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('entity_test_mul');
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// Adding german language.
|
||||
ConfigurableLanguage::create(['id' => 'de'])->save();
|
||||
|
||||
$this->config('language.types')->setData([
|
||||
'configurable' => ['language_interface'],
|
||||
'negotiation' => ['language_interface' => ['enabled' => ['language-url' => 0]]],
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for no canonical link templates.
|
||||
*/
|
||||
public function testNoCanonicalLinkTemplate() {
|
||||
$entity_type = EntityTestTranslatableUISkip::create([
|
||||
'name' => 'name english',
|
||||
'language' => 'en'
|
||||
]);
|
||||
$entity_type->save();
|
||||
|
||||
$entity_type->addTranslation('de', ['name' => 'name german']);
|
||||
$entity_type->save();
|
||||
$this->assertEqual(count($entity_type->getTranslationLanguages()), 2);
|
||||
|
||||
$entity_type->removeTranslation('de');
|
||||
$entity_type->save();
|
||||
$this->assertEqual(count($entity_type->getTranslationLanguages()), 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\path\Unit\Field;
|
||||
|
||||
use Drupal\Tests\Core\Field\BaseFieldDefinitionTestBase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Field\BaseFieldDefinition
|
||||
* @group path
|
||||
*/
|
||||
class PathFieldDefinitionTest extends BaseFieldDefinitionTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getPluginId() {
|
||||
return 'path';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getModuleAndPath() {
|
||||
return array('path', dirname(dirname(dirname(dirname(__DIR__)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getColumns
|
||||
* @covers ::getSchema
|
||||
*/
|
||||
public function testGetColumns() {
|
||||
$this->assertSame(array(), $this->definition->getColumns());
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue