Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
5
core/modules/path/config/schema/path.schema.yml
Normal file
5
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'
|
66
core/modules/path/path.api.php
Normal file
66
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
core/modules/path/path.info.yml
Normal file
7
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
|
25
core/modules/path/path.js
Normal file
25
core/modules/path/path.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file
|
||||
* Attaches behaviors for the Path module.
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.pathDetailsSummaries = {
|
||||
attach: function (context) {
|
||||
$(context).find('.path-form').drupalSetSummary(function (context) {
|
||||
var path = $('.form-item-path-0-alias input').val();
|
||||
|
||||
return path ?
|
||||
Drupal.t('Alias: @alias', {'@alias': path}) :
|
||||
Drupal.t('No alias');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
8
core/modules/path/path.libraries.yml
Normal file
8
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
core/modules/path/path.links.action.yml
Normal file
5
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
core/modules/path/path.links.menu.yml
Normal file
6
core/modules/path/path.links.menu.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
path.admin_overview:
|
||||
title: 'URL aliases'
|
||||
description: 'Change your site''s URL paths by aliasing them.'
|
||||
route_name: path.admin_overview
|
||||
parent: system.admin_config_search
|
||||
weight: -5
|
4
core/modules/path/path.links.task.yml
Normal file
4
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
|
89
core/modules/path/path.module
Normal file
89
core/modules/path/path.module
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Enables users to rename URLs.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\FieldDefinition;
|
||||
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 node_form().
|
||||
*/
|
||||
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)
|
||||
->setCustomStorage(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_translation_delete().
|
||||
*/
|
||||
function path_entity_translation_delete(EntityInterface $translation) {
|
||||
$path = $translation->urlInfo()->getInternalPath();
|
||||
$conditions = array('source' => '/' . $path, 'langcode' => $translation->language()->getId());
|
||||
\Drupal::service('path.alias_storage')->delete($conditions);
|
||||
}
|
4
core/modules/path/path.permissions.yml
Normal file
4
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
core/modules/path/path.routing.yml
Normal file
40
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'
|
138
core/modules/path/src/Controller/PathController.php
Normal file
138
core/modules/path/src/Controller/PathController.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Controller\PathController.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
36
core/modules/path/src/Form/AddForm.php
Normal file
36
core/modules/path/src/Form/AddForm.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Form\AddForm.
|
||||
*/
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
95
core/modules/path/src/Form/DeleteForm.php
Normal file
95
core/modules/path/src/Form/DeleteForm.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Form\DeleteForm.
|
||||
*/
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Form\ConfirmFormBase::getQuestion().
|
||||
*/
|
||||
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');
|
||||
}
|
||||
|
||||
}
|
68
core/modules/path/src/Form/EditForm.php
Normal file
68
core/modules/path/src/Form/EditForm.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Form\EditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\path\Form;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
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'] = SafeMarkup::checkPlain($this->path['alias']);
|
||||
$form['pid'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $this->path['pid'],
|
||||
);
|
||||
$form['actions']['delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Delete'),
|
||||
'#submit' => array('::deleteSubmit'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the delete form.
|
||||
*/
|
||||
public function deleteSubmit(array &$form, FormStateInterface $form_state) {
|
||||
$url = new Url('path.delete', array(
|
||||
'pid' => $form_state->getValue('pid'),
|
||||
));
|
||||
|
||||
if ($this->getRequest()->query->has('destination')) {
|
||||
$url->setOption('query', $this->getDestinationArray());
|
||||
$this->getRequest()->query->remove('destination');
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($url);
|
||||
}
|
||||
|
||||
}
|
75
core/modules/path/src/Form/PathFilterForm.php
Normal file
75
core/modules/path/src/Form/PathFilterForm.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Form\PathFilterForm.
|
||||
*/
|
||||
|
||||
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',
|
||||
'#button_type' => 'primary',
|
||||
'#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');
|
||||
}
|
||||
|
||||
}
|
210
core/modules/path/src/Form/PathFormBase.php
Normal file
210
core/modules/path/src/Form/PathFormBase.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Form\PathFormBase.
|
||||
*/
|
||||
|
||||
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. Use a relative path with a slash in front..'),
|
||||
'#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'),
|
||||
);
|
||||
|
||||
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'])) {
|
||||
$form_state->setErrorByName('alias', t('The alias %alias is already in use in this language.', array('%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,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Plugin\Field\FieldType\PathFieldItemList.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
101
core/modules/path/src/Plugin/Field/FieldType/PathItem.php
Normal file
101
core/modules/path/src/Plugin/Field/FieldType/PathItem.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Plugin\Field\FieldType\PathItem.
|
||||
*/
|
||||
|
||||
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('string')
|
||||
->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 insert() {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function update() {
|
||||
// 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 function delete() {
|
||||
// Delete all aliases associated with this entity.
|
||||
$entity = $this->getEntity();
|
||||
\Drupal::service('path.alias_storage')->delete(array('source' => '/' . $entity->urlInfo()->getInternalPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
|
||||
$random = new Random();
|
||||
$values['alias'] = str_replace(' ', '-', strtolower($random->sentences(3)));
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
111
core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
Normal file
111
core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Plugin\Field\FieldWidget\PathWidget.
|
||||
*/
|
||||
|
||||
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('The alternative URL for this content. Use a relative path. For example, enter "/about" for the 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'];
|
||||
}
|
||||
|
||||
}
|
105
core/modules/path/src/Tests/PathAdminTest.php
Normal file
105
core/modules/path/src/Tests/PathAdminTest.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathAdminTest.
|
||||
*/
|
||||
|
||||
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 login.
|
||||
$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);
|
||||
}
|
||||
|
||||
}
|
305
core/modules/path/src/Tests/PathAliasTest.php
Normal file
305
core/modules/path/src/Tests/PathAliasTest.php
Normal file
|
@ -0,0 +1,305 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathAliasTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\path\Tests;
|
||||
|
||||
/**
|
||||
* 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 login.
|
||||
$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()->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();
|
||||
$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->randomMachineName(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);
|
||||
|
||||
// Change alias to one containing "exotic" characters.
|
||||
$pid = $this->getPID($edit['alias']);
|
||||
|
||||
$previous = $edit['alias'];
|
||||
$edit['alias'] = "/- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
|
||||
"%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
|
||||
"éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
|
||||
$this->drupalPostForm('admin/config/search/path/edit/' . $pid, $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($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.');
|
||||
|
||||
// Delete alias.
|
||||
$this->drupalPostForm('admin/config/search/path/edit/' . $pid, array(), t('Delete'));
|
||||
$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.');
|
||||
|
||||
// Change alias to one containing "exotic" characters.
|
||||
$previous = $edit['path[0][alias]'];
|
||||
$edit['path[0][alias]'] = "/- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
|
||||
"%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
|
||||
"éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
|
||||
$this->drupalPostForm('node/' . $node1->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Confirm that the alias works.
|
||||
$this->drupalGet($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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.');
|
||||
}
|
||||
}
|
195
core/modules/path/src/Tests/PathLanguageTest.php
Normal file
195
core/modules/path/src/Tests/PathLanguageTest.php
Normal file
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathLanguageTest.
|
||||
*/
|
||||
|
||||
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', '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 login 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.');
|
||||
}
|
||||
}
|
85
core/modules/path/src/Tests/PathLanguageUiTest.php
Normal file
85
core/modules/path/src/Tests/PathLanguageUiTest.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathLanguageUiTest.
|
||||
*/
|
||||
|
||||
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');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create and login 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');
|
||||
}
|
||||
}
|
54
core/modules/path/src/Tests/PathNodeFormTest.php
Normal file
54
core/modules/path/src/Tests/PathNodeFormTest.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathNodeFormTest.
|
||||
*/
|
||||
|
||||
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 login.
|
||||
$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');
|
||||
}
|
||||
|
||||
}
|
90
core/modules/path/src/Tests/PathTaxonomyTermTest.php
Normal file
90
core/modules/path/src/Tests/PathTaxonomyTermTest.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathTaxonomyTermTest.
|
||||
*/
|
||||
|
||||
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 = entity_create('taxonomy_vocabulary', array(
|
||||
'name' => t('Tags'),
|
||||
'vid' => 'tags',
|
||||
));
|
||||
$vocabulary->save();
|
||||
|
||||
// Create and login 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.');
|
||||
}
|
||||
}
|
33
core/modules/path/src/Tests/PathTestBase.php
Normal file
33
core/modules/path/src/Tests/PathTestBase.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\path\Tests\PathTestBase.
|
||||
*/
|
||||
|
||||
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,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\path\Unit\Field\PathFieldDefinitionTest.
|
||||
*/
|
||||
|
||||
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