updated core to 8.6.1 via composer

This commit is contained in:
2018-09-12 13:58:26 +02:00
parent a9a219f2ed
commit ea56b9fba3
4443 changed files with 112098 additions and 40708 deletions
-1
View File
@@ -4,7 +4,6 @@
table.diff {
border-spacing: 4px;
margin-bottom: 20px;
table-layout: fixed;
width: 100%;
}
table.diff .diff-context {
+17 -6
View File
@@ -3,7 +3,7 @@
* Provides date format preview feature.
*/
(function ($, Drupal, drupalSettings) {
(function($, Drupal, drupalSettings) {
const dateFormats = drupalSettings.dateFormats;
/**
@@ -17,8 +17,12 @@
Drupal.behaviors.dateFormat = {
attach(context) {
const $context = $(context);
const $source = $context.find('[data-drupal-date-formatter="source"]').once('dateFormat');
const $target = $context.find('[data-drupal-date-formatter="preview"]').once('dateFormat');
const $source = $context
.find('[data-drupal-date-formatter="source"]')
.once('dateFormat');
const $target = $context
.find('[data-drupal-date-formatter="preview"]')
.once('dateFormat');
const $preview = $target.find('em');
// All elements have to exist.
@@ -34,7 +38,10 @@
*/
function dateFormatHandler(e) {
const baseValue = $(e.target).val() || '';
const dateString = baseValue.replace(/\\?(.?)/gi, (key, value) => (dateFormats[key] ? dateFormats[key] : value));
const dateString = baseValue.replace(
/\\?(.?)/gi,
(key, value) => (dateFormats[key] ? dateFormats[key] : value),
);
$preview.html(dateString);
$target.toggleClass('js-hide', !dateString.length);
@@ -43,9 +50,13 @@
/**
* On given event triggers the date character replacement.
*/
$source.on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler)
$source
.on(
'keyup.dateFormat change.dateFormat input.dateFormat',
dateFormatHandler,
)
// Initialize preview.
.trigger('keyup');
},
};
}(jQuery, Drupal, drupalSettings));
})(jQuery, Drupal, drupalSettings);
+15 -7
View File
@@ -3,7 +3,7 @@
* System behaviors.
*/
(function ($, Drupal, drupalSettings) {
(function($, Drupal, drupalSettings) {
// Cache IDs in an array for ease of use.
const ids = [];
@@ -23,7 +23,7 @@
attach(context) {
// List of fields IDs on which to bind the event listener.
// Create an array of IDs to use with jQuery.
Object.keys(drupalSettings.copyFieldValue || {}).forEach((element) => {
Object.keys(drupalSettings.copyFieldValue || {}).forEach(element => {
ids.push(element);
});
@@ -31,15 +31,23 @@
// Listen to value:copy events on all dependent fields.
// We have to use body and not document because of the way jQuery events
// bubble up the DOM tree.
$('body').once('copy-field-values').on('value:copy', this.valueTargetCopyHandler);
$('body')
.once('copy-field-values')
.on('value:copy', this.valueTargetCopyHandler);
// Listen on all source elements.
$(`#${ids.join(', #')}`).once('copy-field-values').on('blur', this.valueSourceBlurHandler);
$(`#${ids.join(', #')}`)
.once('copy-field-values')
.on('blur', this.valueSourceBlurHandler);
}
},
detach(context, settings, trigger) {
if (trigger === 'unload' && ids.length) {
$('body').removeOnce('copy-field-values').off('value:copy');
$(`#${ids.join(', #')}`).removeOnce('copy-field-values').off('blur');
$('body')
.removeOnce('copy-field-values')
.off('value:copy');
$(`#${ids.join(', #')}`)
.removeOnce('copy-field-values')
.off('blur');
}
},
@@ -73,4 +81,4 @@
$(`#${targetIds.join(', #')}`).trigger('value:copy', value);
},
};
}(jQuery, Drupal, drupalSettings));
})(jQuery, Drupal, drupalSettings);
+14 -11
View File
@@ -3,7 +3,7 @@
* Module page behaviors.
*/
(function ($, Drupal, debounce) {
(function($, Drupal, debounce) {
/**
* Filters the module list table by a text input search string.
*
@@ -38,7 +38,9 @@
function showModuleRow(index, row) {
const $row = $(row);
const $sources = $row.find('.table-filter-text-source, .module-name, .module-description');
const $sources = $row.find(
'.table-filter-text-source, .module-name, .module-description',
);
const textMatch = $sources.text().search(re) !== -1;
$row.closest('tr').toggle(textMatch);
}
@@ -53,25 +55,26 @@
// Note that we first open all <details> to be able to use ':visible'.
// Mark the <details> elements that were closed before filtering, so
// they can be reclosed when filtering is removed.
$details.not('[open]').attr('data-drupal-system-state', 'forced-open');
$details
.not('[open]')
.attr('data-drupal-system-state', 'forced-open');
// Hide the package <details> if they don't have any visible rows.
// Note that we first show() all <details> to be able to use ':visible'.
$details.attr('open', true).each(hidePackageDetails);
Drupal.announce(
Drupal.t(
'!modules modules are available in the modified list.',
{ '!modules': $rowsAndDetails.find('tbody tr:visible').length },
),
Drupal.t('!modules modules are available in the modified list.', {
'!modules': $rowsAndDetails.find('tbody tr:visible').length,
}),
);
}
else if (searching) {
} else if (searching) {
searching = false;
$rowsAndDetails.show();
// Return <details> elements that had been closed before filtering
// to a closed state.
$details.filter('[data-drupal-system-state="forced-open"]')
$details
.filter('[data-drupal-system-state="forced-open"]')
.removeAttr('data-drupal-system-state')
.attr('open', false);
}
@@ -96,4 +99,4 @@
}
},
};
}(jQuery, Drupal, Drupal.debounce));
})(jQuery, Drupal, Drupal.debounce);
+3 -1
View File
@@ -43,7 +43,9 @@
$details.attr('open', true).each(hidePackageDetails);
Drupal.announce(Drupal.t('!modules modules are available in the modified list.', { '!modules': $rowsAndDetails.find('tbody tr:visible').length }));
Drupal.announce(Drupal.t('!modules modules are available in the modified list.', {
'!modules': $rowsAndDetails.find('tbody tr:visible').length
}));
} else if (searching) {
searching = false;
$rowsAndDetails.show();
@@ -335,11 +335,11 @@ class DbUpdateController extends ControllerBase {
// Warn the user if any updates were incompatible.
if ($incompatible_updates_exist) {
drupal_set_message($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'), 'warning');
$this->messenger()->addWarning($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'));
}
if (empty($count)) {
drupal_set_message($this->t('No pending updates.'));
$this->messenger()->addStatus($this->t('No pending updates.'));
unset($build);
$build['links'] = [
'#theme' => 'links',
@@ -524,7 +524,7 @@ class DbUpdateController extends ControllerBase {
$build['status_report'] = [
'#type' => 'status_report',
'#requirements' => $requirements,
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url])
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url]),
];
$build['#title'] = $this->t('Requirements problem');
@@ -4,7 +4,6 @@ namespace Drupal\system\Controller;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Tags;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityAutocompleteMatcher;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
@@ -81,7 +80,7 @@ class EntityAutocompleteController extends ControllerBase {
// Get the typed string from the URL, if it exists.
if ($input = $request->query->get('q')) {
$typed_string = Tags::explode($input);
$typed_string = Unicode::strtolower(array_pop($typed_string));
$typed_string = mb_strtolower(array_pop($typed_string));
// Selection settings are passed in as a hashed key of a serialized array
// stored in the key/value store.
@@ -100,7 +100,7 @@ class SystemController extends ControllerBase {
public function overview($link_id) {
// Check for status report errors.
if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href=":status">status report</a> for more information.', [':status' => $this->url('system.status')]), 'error');
$this->messenger()->addError($this->t('One or more problems were detected with your Drupal installation. Check the <a href=":status">status report</a> for more information.', [':status' => $this->url('system.status')]));
}
// Load all menu links below it.
$parameters = new MenuTreeParameters();
@@ -187,7 +187,7 @@ class SystemController extends ControllerBase {
uasort($themes, 'system_sort_modules_by_info_name');
$theme_default = $config->get('default');
$theme_groups = ['installed' => [], 'uninstalled' => []];
$theme_groups = ['installed' => [], 'uninstalled' => []];
$admin_theme = $config->get('admin');
$admin_theme_options = [];
@@ -71,15 +71,15 @@ class ThemeController extends ControllerBase {
if (!empty($themes[$theme])) {
// Do not uninstall the default or admin theme.
if ($theme === $config->get('default') || $theme === $config->get('admin')) {
drupal_set_message($this->t('%theme is the default theme and cannot be uninstalled.', ['%theme' => $themes[$theme]->info['name']]), 'error');
$this->messenger()->addError($this->t('%theme is the default theme and cannot be uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
}
else {
$this->themeHandler->uninstall([$theme]);
drupal_set_message($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
$this->messenger()->addStatus($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
}
}
else {
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
}
return $this->redirect('system.themes_page');
@@ -108,15 +108,15 @@ class ThemeController extends ControllerBase {
try {
if ($this->themeHandler->install([$theme])) {
$themes = $this->themeHandler->listInfo();
drupal_set_message($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
$this->messenger()->addStatus($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
}
else {
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
}
}
catch (PreExistingConfigException $e) {
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
drupal_set_message(
$this->messenger()->addError(
$this->formatPlural(
count($config_objects),
'Unable to install @extension, %config_names already exists in active configuration.',
@@ -124,12 +124,11 @@ class ThemeController extends ControllerBase {
[
'%config_names' => implode(', ', $config_objects),
'@extension' => $theme,
]),
'error'
])
);
}
catch (UnmetDependenciesException $e) {
drupal_set_message($e->getTranslatedMessage($this->getStringTranslation(), $theme), 'error');
$this->messenger()->addError($e->getTranslatedMessage($this->getStringTranslation(), $theme));
}
return $this->redirect('system.themes_page');
@@ -171,17 +170,18 @@ class ThemeController extends ControllerBase {
// theme.
$admin_theme = $config->get('admin');
if ($admin_theme != 0 && $admin_theme != $theme) {
drupal_set_message($this->t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', [
'%admin_theme' => $themes[$admin_theme]->info['name'],
'%selected_theme' => $themes[$theme]->info['name'],
]));
$this->messenger()
->addStatus($this->t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', [
'%admin_theme' => $themes[$admin_theme]->info['name'],
'%selected_theme' => $themes[$theme]->info['name'],
]));
}
else {
drupal_set_message($this->t('%theme is now the default theme.', ['%theme' => $themes[$theme]->info['name']]));
$this->messenger()->addStatus($this->t('%theme is now the default theme.', ['%theme' => $themes[$theme]->info['name']]));
}
}
else {
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
}
return $this->redirect('system.themes_page');
+2 -3
View File
@@ -36,7 +36,6 @@ class CronController extends ControllerBase {
return new static($container->get('cron'));
}
/**
* Run Cron once.
*
@@ -58,10 +57,10 @@ class CronController extends ControllerBase {
*/
public function runManually() {
if ($this->cron->run()) {
drupal_set_message($this->t('Cron ran successfully.'));
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
}
else {
drupal_set_message($this->t('Cron run failed.'), 'error');
$this->messenger()->addError($this->t('Cron run failed.'));
}
return $this->redirect('system.status');
@@ -15,6 +15,13 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface;
* @ConfigEntityType(
* id = "action",
* label = @Translation("Action"),
* label_collection = @Translation("Actions"),
* label_singular = @Translation("action"),
* label_plural = @Translation("actions"),
* label_count = @PluralTranslation(
* singular = "@count action",
* plural = "@count actions",
* ),
* admin_permission = "administer actions",
* entity_keys = {
* "id" = "id",
+47
View File
@@ -3,6 +3,7 @@
namespace Drupal\system\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\system\MenuInterface;
/**
@@ -11,6 +12,13 @@ use Drupal\system\MenuInterface;
* @ConfigEntityType(
* id = "menu",
* label = @Translation("Menu"),
* label_collection = @Translation("Menus"),
* label_singular = @Translation("menu"),
* label_plural = @Translation("menus"),
* label_count = @PluralTranslation(
* singular = "@count menu",
* plural = "@count menus",
* ),
* handlers = {
* "access" = "Drupal\system\MenuAccessControlHandler"
* },
@@ -71,4 +79,43 @@ class Menu extends ConfigEntityBase implements MenuInterface {
return (bool) $this->locked;
}
/**
* {@inheritdoc}
*/
public static function preDelete(EntityStorageInterface $storage, array $entities) {
parent::preDelete($storage, $entities);
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
foreach ($entities as $menu) {
// Delete all links from the menu.
$menu_link_manager->deleteLinksInMenu($menu->id());
}
}
/**
* {@inheritdoc}
*/
public function save() {
$return = parent::save();
\Drupal::cache('menu')->invalidateAll();
// Invalidate the block cache to update menu-based derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
return $return;
}
/**
* {@inheritdoc}
*/
public function delete() {
parent::delete();
\Drupal::cache('menu')->invalidateAll();
// Invalidate the block cache to update menu-based derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
}
}
+3 -3
View File
@@ -155,7 +155,7 @@ class CronForm extends FormBase {
$this->config('system.cron')
->set('logging', $form_state->getValue('logging'))
->save();
drupal_set_message(t('The configuration options have been saved.'));
$this->messenger()->addStatus(t('The configuration options have been saved.'));
}
/**
@@ -163,10 +163,10 @@ class CronForm extends FormBase {
*/
public function runCron(array &$form, FormStateInterface $form_state) {
if ($this->cron->run()) {
drupal_set_message($this->t('Cron ran successfully.'));
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
}
else {
drupal_set_message($this->t('Cron run failed.'), 'error');
$this->messenger()->addError($this->t('Cron run failed.'));
}
}
@@ -129,7 +129,7 @@ abstract class DateFormatFormBase extends EntityForm {
$pattern = trim($form_state->getValue('date_format_pattern'));
foreach ($this->dateFormatStorage->loadMultiple() as $format) {
if ($format->getPattern() == $pattern && ($format->id() == $this->entity->id())) {
drupal_set_message(t('The existing format/name combination has not been altered.'));
$this->messenger()->addStatus($this->t('The existing format/name combination has not been altered.'));
continue;
}
}
@@ -149,10 +149,10 @@ abstract class DateFormatFormBase extends EntityForm {
public function save(array $form, FormStateInterface $form_state) {
$status = $this->entity->save();
if ($status == SAVED_UPDATED) {
drupal_set_message(t('Custom date format updated.'));
$this->messenger()->addStatus($this->t('Custom date format updated.'));
}
else {
drupal_set_message(t('Custom date format added.'));
$this->messenger()->addStatus($this->t('Custom date format added.'));
}
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
}
@@ -174,29 +174,27 @@ class ModulesListConfirmForm extends ConfirmFormBase {
}
catch (PreExistingConfigException $e) {
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
drupal_set_message(
$this->messenger()->addError(
$this->formatPlural(
count($config_objects),
'Unable to install @extension, %config_names already exists in active configuration.',
'Unable to install @extension, %config_names already exist in active configuration.',
[
'%config_names' => implode(', ', $config_objects),
'@extension' => $this->modules['install'][$e->getExtension()]
]),
'error'
'@extension' => $this->modules['install'][$e->getExtension()],
])
);
return;
}
catch (UnmetDependenciesException $e) {
drupal_set_message(
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()]),
'error'
$this->messenger()->addError(
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()])
);
return;
}
$module_names = array_values($this->modules['install']);
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
'%name' => $module_names[0],
'%names' => implode(', ', $module_names),
]));
@@ -27,7 +27,7 @@ class ModulesListExperimentalConfirmForm extends ModulesListConfirmForm {
* {@inheritdoc}
*/
protected function buildMessageList() {
drupal_set_message($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']), 'warning');
$this->messenger()->addWarning($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']));
$items = parent::buildMessageList();
// Add the list of experimental modules after any other messages.
@@ -450,30 +450,28 @@ class ModulesListForm extends FormBase {
try {
$this->moduleInstaller->install(array_keys($modules['install']));
$module_names = array_values($modules['install']);
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
'%name' => $module_names[0],
'%names' => implode(', ', $module_names),
]));
}
catch (PreExistingConfigException $e) {
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
drupal_set_message(
$this->messenger()->addError(
$this->formatPlural(
count($config_objects),
'Unable to install @extension, %config_names already exists in active configuration.',
'Unable to install @extension, %config_names already exist in active configuration.',
[
'%config_names' => implode(', ', $config_objects),
'@extension' => $modules['install'][$e->getExtension()]
]),
'error'
'@extension' => $modules['install'][$e->getExtension()],
])
);
return;
}
catch (UnmetDependenciesException $e) {
drupal_set_message(
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()]),
'error'
$this->messenger()->addError(
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()])
);
return;
}
@@ -131,7 +131,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
// Prevent this page from showing when the module list is empty.
if (empty($this->modules)) {
drupal_set_message($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'), 'error');
$this->messenger()->addError($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'));
return $this->redirect('system.modules_uninstall');
}
@@ -161,7 +161,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
// Uninstall the modules.
$this->moduleInstaller->uninstall($this->modules);
drupal_set_message($this->t('The selected modules have been uninstalled.'));
$this->messenger()->addStatus($this->t('The selected modules have been uninstalled.'));
$form_state->setRedirectUrl($this->getCancelUrl());
}
@@ -116,8 +116,6 @@ class ModulesUninstallForm extends FormBase {
return $form;
}
$profile = drupal_get_profile();
// Sort all modules by their name.
uasort($uninstallable, 'system_sort_modules_by_info_name');
$validation_reasons = $this->moduleInstaller->validateUninstall(array_keys($uninstallable));
@@ -142,10 +140,9 @@ class ModulesUninstallForm extends FormBase {
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
}
// All modules which depend on this one must be uninstalled first, before
// we can allow this module to be uninstalled. (The installation profile
// is excluded from this list.)
// we can allow this module to be uninstalled.
foreach (array_keys($module->required_by) as $dependent) {
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
if (drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
$name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent;
$form['modules'][$module->getName()]['#required_by'][] = $name;
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
@@ -3,10 +3,12 @@
namespace Drupal\system\Form;
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -37,6 +39,13 @@ class PerformanceForm extends ConfigFormBase {
*/
protected $jsCollectionOptimizer;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a PerformanceForm object.
*
@@ -48,13 +57,16 @@ class PerformanceForm extends ConfigFormBase {
* The CSS asset collection optimizer service.
* @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $js_collection_optimizer
* The JavaScript asset collection optimizer service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer) {
public function __construct(ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer, ModuleHandlerInterface $module_handler) {
parent::__construct($config_factory);
$this->dateFormatter = $date_formatter;
$this->cssCollectionOptimizer = $css_collection_optimizer;
$this->jsCollectionOptimizer = $js_collection_optimizer;
$this->moduleHandler = $module_handler;
}
/**
@@ -65,7 +77,8 @@ class PerformanceForm extends ConfigFormBase {
$container->get('config.factory'),
$container->get('date.formatter'),
$container->get('asset.css.collection_optimizer'),
$container->get('asset.js.collection_optimizer')
$container->get('asset.js.collection_optimizer'),
$container->get('module_handler')
);
}
@@ -107,7 +120,6 @@ class PerformanceForm extends ConfigFormBase {
'#type' => 'details',
'#title' => t('Caching'),
'#open' => TRUE,
'#description' => $this->t('Note: Drupal provides an internal page cache module that is recommended for small to medium-sized websites.'),
];
// Identical options to the ones for block caching.
// @see \Drupal\Core\Block\BlockBase::buildConfigurationForm()
@@ -116,10 +128,14 @@ class PerformanceForm extends ConfigFormBase {
$period[0] = '<' . t('no caching') . '>';
$form['caching']['page_cache_maximum_age'] = [
'#type' => 'select',
'#title' => t('Page cache maximum age'),
'#title' => t('Browser and proxy cache maximum age'),
'#default_value' => $config->get('cache.page.max_age'),
'#options' => $period,
'#description' => t('The maximum time a page can be cached by browsers and proxies. This is used as the value for max-age in Cache-Control headers.'),
'#description' => t('This is used as the value for max-age in Cache-Control headers.'),
];
$form['caching']['internal_page_cache'] = [
'#markup' => $this->t('Drupal provides an <a href=":module_enable">Internal Page Cache module</a> that is recommended for small to medium-sized websites.', [':module_enable' => Url::fromRoute('system.modules_list')->toString()]),
'#access' => !$this->moduleHandler->moduleExists('page_cache'),
];
$directory = 'public://';
@@ -174,7 +190,7 @@ class PerformanceForm extends ConfigFormBase {
*/
public function submitCacheClear(array &$form, FormStateInterface $form_state) {
drupal_flush_all_caches();
drupal_set_message(t('Caches cleared.'));
$this->messenger()->addStatus($this->t('Caches cleared.'));
}
}
@@ -159,7 +159,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
'@entity_type_singular' => $entity_type->getSingularLabel(),
'@entity_type_plural' => $entity_type->getPluralLabel(),
]
)
),
];
}
@@ -250,7 +250,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
*/
public static function moduleBatchFinished($success, $results, $operations) {
$entity_type_plural = \Drupal::entityTypeManager()->getDefinition($results['entity_type_id'])->getPluralLabel();
drupal_set_message(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
\Drupal::messenger()->addStatus(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
return new RedirectResponse(Url::fromRoute('system.modules_uninstall')->setAbsolute()->toString());
}
@@ -125,7 +125,7 @@ class RegionalForm extends ConfigFormBase {
'#type' => 'checkbox',
'#title' => t('Remind users at login if their time zone is not set'),
'#default_value' => $system_date->get('timezone.user.warn'),
'#description' => t('Only applied if users may set their own time zone.')
'#description' => t('Only applied if users may set their own time zone.'),
];
$form['timezone']['configurable_timezones_wrapper']['user_default_timezone'] = [
@@ -137,7 +137,7 @@ class RegionalForm extends ConfigFormBase {
DRUPAL_USER_TIMEZONE_EMPTY => t('Empty time zone'),
DRUPAL_USER_TIMEZONE_SELECT => t('Users may set their own time zone at registration'),
],
'#description' => t('Only applied if users may set their own time zone.')
'#description' => t('Only applied if users may set their own time zone.'),
];
return parent::buildForm($form, $form_state);
@@ -35,7 +35,7 @@ class RssFeedsForm extends ConfigFormBase {
'#type' => 'textarea',
'#title' => t('Feed description'),
'#default_value' => $rss_config->get('channel.description'),
'#description' => t('Description of your site, included in each feed.')
'#description' => t('Description of your site, included in each feed.'),
];
$options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30];
$form['feed_default_items'] = [
@@ -43,7 +43,7 @@ class RssFeedsForm extends ConfigFormBase {
'#title' => t('Number of items in each feed'),
'#default_value' => $rss_config->get('items.limit'),
'#options' => array_combine($options, $options),
'#description' => t('Default number of items to include in each feed.')
'#description' => t('Default number of items to include in each feed.'),
];
$form['feed_view_mode'] = [
'#type' => 'select',
@@ -54,7 +54,7 @@ class RssFeedsForm extends ConfigFormBase {
'teaser' => t('Titles plus teaser'),
'fulltext' => t('Full text'),
],
'#description' => t('Global setting for the default display of content items in each feed.')
'#description' => t('Global setting for the default display of content items in each feed.'),
];
return parent::buildForm($form, $form_state);
@@ -56,6 +56,7 @@ class SiteMaintenanceModeForm extends ConfigFormBase {
$container->get('user.permissions')
);
}
/**
* {@inheritdoc}
*/
@@ -136,11 +136,11 @@ class ThemeSettingsForm extends ConfigFormBase {
$form['var'] = [
'#type' => 'hidden',
'#value' => $var
'#value' => $var,
];
$form['config_key'] = [
'#type' => 'hidden',
'#value' => $config_key
'#value' => $config_key,
];
// Toggle settings
@@ -377,22 +377,23 @@ class ThemeSettingsForm extends ConfigFormBase {
parent::validateForm($form, $form_state);
if ($this->moduleHandler->moduleExists('file')) {
$validators = ['file_validate_is_image' => []];
// Check for a new uploaded logo.
$file = _file_save_upload_from_form($form['logo']['settings']['logo_upload'], $form_state, 0);
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state->setValue('logo_upload', $file);
if (isset($form['logo'])) {
$file = _file_save_upload_from_form($form['logo']['settings']['logo_upload'], $form_state, 0);
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state->setValue('logo_upload', $file);
}
}
$validators = ['file_validate_extensions' => ['ico png gif jpg jpeg apng svg']];
// Check for a new uploaded favicon.
$file = _file_save_upload_from_form($form['favicon']['settings']['favicon_upload'], $form_state, 0);
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state->setValue('favicon_upload', $file);
if (isset($form['favicon'])) {
$file = _file_save_upload_from_form($form['favicon']['settings']['favicon_upload'], $form_state, 0);
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state->setValue('favicon_upload', $file);
}
}
// When intending to use the default logo, unset the logo_path.
@@ -3,7 +3,6 @@
namespace Drupal\system;
use Drupal\Component\Transliteration\TransliterationInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -73,7 +72,7 @@ class MachineNameController implements ContainerInjectionInterface {
$transliterated = $this->transliteration->transliterate($text, $langcode, '_');
if ($lowercase) {
$transliterated = Unicode::strtolower($transliterated);
$transliterated = mb_strtolower($transliterated);
}
if (isset($replace_pattern) && isset($replace)) {
@@ -9,7 +9,7 @@ use Drupal\Core\Cache\Cache;
/**
* Provides a block to display the messages.
*
* @see drupal_set_message()
* @see @see \Drupal\Core\Messenger\MessengerInterface
*
* @Block(
* id = "system_messages_block",
@@ -2,7 +2,6 @@
namespace Drupal\system\Plugin\Condition;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\AliasManagerInterface;
@@ -139,7 +138,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
public function evaluate() {
// Convert path to lowercase. This allows comparison of the same path
// with different case. Ex: /Page, /page, /PAGE.
$pages = Unicode::strtolower($this->configuration['pages']);
$pages = mb_strtolower($this->configuration['pages']);
if (!$pages) {
return TRUE;
}
@@ -149,7 +148,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
$path = $this->currentPath->getPath($request);
// Do not trim a trailing slash if that is the complete path.
$path = $path === '/' ? $path : rtrim($path, '/');
$path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path));
$path_alias = mb_strtolower($this->aliasManager->getAliasByPath($path));
return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
}
@@ -3,7 +3,6 @@
namespace Drupal\system\Plugin\ImageToolkit;
use Drupal\Component\Utility\Color;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\ImageToolkit\ImageToolkitBase;
@@ -395,7 +394,7 @@ class GDToolkit extends ImageToolkitBase {
foreach (static::supportedTypes() as $image_type) {
// @todo Automatically fetch possible extensions for each mime type.
// @see https://www.drupal.org/node/2311679
$extension = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
$extension = mb_strtolower(image_type_to_extension($image_type, FALSE));
$extensions[] = $extension;
// Add some known similar extensions.
if ($extension === 'jpeg') {
@@ -20,6 +20,16 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
*/
protected function arguments() {
return [
'x' => [
'description' => 'The horizontal offset for the start of the crop, in pixels',
'required' => FALSE,
'default' => NULL,
],
'y' => [
'description' => 'The vertical offset for the start the crop, in pixels',
'required' => FALSE,
'default' => NULL,
],
'width' => [
'description' => 'The target width, in pixels',
],
@@ -38,8 +48,12 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
$scaleFactor = max($arguments['width'] / $actualWidth, $arguments['height'] / $actualHeight);
$arguments['x'] = (int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
$arguments['y'] = (int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
$arguments['x'] = isset($arguments['x']) ?
(int) round($arguments['x']) :
(int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
$arguments['y'] = isset($arguments['y']) ?
(int) round($arguments['y']) :
(int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
$arguments['resize'] = [
'width' => (int) round($actualWidth * $scaleFactor),
'height' => (int) round($actualHeight * $scaleFactor),
@@ -14,6 +14,7 @@ use Drupal\migrate\Row;
* )
*/
class TimeZone extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
@@ -0,0 +1,66 @@
<?php
namespace Drupal\system\Plugin\migrate\source;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Gets system data for a legacy extension.
*
* @MigrateSource(
* id = "extension",
* source_module = "system"
* )
*/
class Extension extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('system', 's')
->fields('s');
if (isset($this->configuration['name'])) {
$query->condition('name', (array) $this->configuration['name'], 'IN');
}
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = [
'filename' => $this->t('Filename'),
'name' => $this->t('Name'),
'type' => $this->t('Type'),
'owner' => $this->t('Owner'),
'status' => $this->t('Status'),
'throttle' => $this->t('Throttle'),
'bootstrap' => $this->t('Bootstrap'),
'schema_version' => $this->t('Schema version'),
'weight' => $this->t('Weight'),
'info' => $this->t('Information array'),
];
return $fields;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$row->setSourceProperty('info', unserialize($row->getSourceProperty('info')));
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['name']['type'] = 'string';
return $ids;
}
}
@@ -72,6 +72,9 @@ class SystemConfigSubscriber implements EventSubscriberInterface {
* The config import event.
*/
public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) {
if (!$event->getConfigImporter()->getStorageComparer()->getSourceStorage()->exists('system.site')) {
$event->getConfigImporter()->logError($this->t('This import does not contain system.site configuration, so has been rejected.'));
}
if (!$event->getConfigImporter()->getStorageComparer()->validateSiteUuid()) {
$event->getConfigImporter()->logError($this->t('Site UUID in source storage does not match the target storage.'));
}
+2 -1
View File
@@ -152,7 +152,8 @@ class SystemManager {
* hidden, so we supply the contents of the block.
*
* @return array
* A render array suitable for drupal_render.
* A render array suitable for
* \Drupal\Core\Render\RendererInterface::render().
*/
public function getBlockContents() {
// We hard-code the menu name here since otherwise a link in the tools menu
@@ -1,77 +0,0 @@
<?php
namespace Drupal\system\Tests\Ajax;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Url;
/**
* Tests the usage of form caching for AJAX forms.
*
* @group Ajax
*/
class AjaxFormCacheTest extends AjaxTestBase {
/**
* Tests the usage of form cache for AJAX forms.
*/
public function testFormCacheUsage() {
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable */
$key_value_expirable = \Drupal::service('keyvalue.expirable')->get('form');
$this->drupalLogin($this->rootUser);
// Ensure that the cache is empty.
$this->assertEqual(0, count($key_value_expirable->getAll()));
// Visit an AJAX form that is not cached, 3 times.
$uncached_form_url = Url::fromRoute('ajax_forms_test.commands_form');
$this->drupalGet($uncached_form_url);
$this->drupalGet($uncached_form_url);
$this->drupalGet($uncached_form_url);
// The number of cache entries should not have changed.
$this->assertEqual(0, count($key_value_expirable->getAll()));
}
/**
* Tests AJAX forms in blocks.
*/
public function testBlockForms() {
$this->container->get('module_installer')->install(['block', 'search']);
$this->rebuildContainer();
$this->container->get('router.builder')->rebuild();
$this->drupalLogin($this->rootUser);
$this->drupalPlaceBlock('search_form_block', ['weight' => -5]);
$this->drupalPlaceBlock('ajax_forms_test_block');
$this->drupalGet('');
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
$this->assertOptionSelectedWithDrupalSelector('edit-test1', 'option1');
$this->assertOptionWithDrupalSelector('edit-test1', 'option3');
$this->drupalPostForm(NULL, ['test1' => 'option1'], 'Submit');
$this->assertText('Submission successful.');
}
/**
* Tests AJAX forms on pages with a query string.
*/
public function testQueryString() {
$this->container->get('module_installer')->install(['block']);
$this->drupalLogin($this->rootUser);
$this->drupalPlaceBlock('ajax_forms_test_block');
$url = Url::fromRoute('entity.user.canonical', ['user' => $this->rootUser->id()], ['query' => ['foo' => 'bar']]);
$this->drupalGet($url);
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
$url->setOption('query', [
'foo' => 'bar',
FormBuilderInterface::AJAX_FORM_REQUEST => 1,
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax',
]);
$this->assertUrl($url);
}
}
@@ -1,32 +0,0 @@
<?php
namespace Drupal\system\Tests\Ajax;
/**
* Tests that form elements in groups work correctly with AJAX.
*
* @group Ajax
*/
class AjaxInGroupTest extends AjaxTestBase {
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser(['access content']));
}
/**
* Submits forms with select and checkbox elements via Ajax.
*/
public function testSimpleAjaxFormValue() {
$this->drupalGet('/ajax_forms_test_get_form');
$this->assertText('Test group');
$this->assertText('AJAX checkbox in a group');
$this->drupalPostAjaxForm(NULL, ['checkbox_in_group' => TRUE], 'checkbox_in_group');
$this->assertText('Test group');
$this->assertText('AJAX checkbox in a group');
$this->assertText('AJAX checkbox in a nested group');
$this->assertText('Another AJAX checkbox in a nested group');
}
}
@@ -29,6 +29,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
* @group Ajax
*/
class CommandsTest extends AjaxTestBase {
/**
* Tests the various Ajax Commands.
*/
@@ -114,7 +114,7 @@ class DialogTest extends AjaxTestBase {
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
'submit' => [
'dialogOptions[target]' => 'ajax-test-dialog-wrapper-1',
]
],
]);
$this->assertEqual($normal_expected_response, $ajax_result[3], 'Normal dialog JSON response matches.');
@@ -126,7 +126,7 @@ class DialogTest extends AjaxTestBase {
'textfield' => 'test',
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
// Don't send a target.
'submit' => []
'submit' => [],
]);
// Make sure the selector ID starts with the right string.
$this->assert(strpos($ajax_result[3]['selector'], $no_target_expected_response['selector']) === 0, 'Selector starts with right string.');
@@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Ajax;
* @group Ajax
*/
class ElementValidationTest extends AjaxTestBase {
/**
* Tries to post an Ajax change to a form that has a validated element.
*
@@ -10,6 +10,7 @@ use Drupal\Core\Ajax\DataCommand;
* @group Ajax
*/
class FormValuesTest extends AjaxTestBase {
protected function setUp() {
parent::setUp();
@@ -16,6 +16,7 @@ use Drupal\Core\Asset\AttachedAssets;
* @group Ajax
*/
class FrameworkTest extends AjaxTestBase {
/**
* Verifies the Ajax rendering of a command in the settings.
*/
@@ -1,27 +0,0 @@
<?php
namespace Drupal\system\Tests\Bootstrap;
use Drupal\Core\DependencyInjection\Container;
/**
* Container base class which triggers an error.
*/
class ErrorContainer extends Container {
/**
* {@inheritdoc}
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
if ($id === 'http_kernel') {
// Enforce a recoverable error.
$callable = function (ErrorContainer $container) {
};
$callable(1);
}
else {
return parent::get($id, $invalidBehavior);
}
}
}
@@ -1,24 +0,0 @@
<?php
namespace Drupal\system\Tests\Bootstrap;
use Drupal\Core\DependencyInjection\Container;
/**
* Base container which throws an exception.
*/
class ExceptionContainer extends Container {
/**
* {@inheritdoc}
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
if ($id === 'http_kernel') {
throw new \Exception('Thrown exception during Container::get');
}
else {
return parent::get($id, $invalidBehavior);
}
}
}
@@ -4,7 +4,7 @@ namespace Drupal\system\Tests\Cache;
use Drupal\Core\Url;
use Drupal\simpletest\WebTestBase;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
/**
* Provides helper methods for page cache tags tests.
@@ -47,7 +47,7 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
*/
protected function verifyPageCache(Url $url, $hit_or_miss, $tags = FALSE) {
$this->drupalGet($url);
$message = SafeMarkup::format('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
$message = new FormattableMarkup('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), $hit_or_miss, $message);
if ($hit_or_miss === 'HIT' && is_array($tags)) {
@@ -1,94 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\simpletest\WebTestBase;
/**
* Tests SimpleTest error and exception collector.
*
* @group Common
*/
class SimpleTestErrorCollectorTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['system_test', 'error_test'];
/**
* Errors triggered during the test.
*
* Errors are intercepted by the overridden implementation
* of Drupal\simpletest\WebTestBase::error() below.
*
* @var Array
*/
protected $collectedErrors = [];
/**
* Tests that simpletest collects errors from the tested site.
*/
public function testErrorCollect() {
$this->collectedErrors = [];
$this->drupalGet('error-test/generate-warnings-with-report');
$this->assertEqual(count($this->collectedErrors), 3, 'Three errors were collected');
if (count($this->collectedErrors) == 3) {
$this->assertError($this->collectedErrors[0], 'Notice', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Undefined variable: bananas');
$this->assertError($this->collectedErrors[1], 'Warning', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Division by zero');
$this->assertError($this->collectedErrors[2], 'User warning', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Drupal &amp; awesome');
}
else {
// Give back the errors to the log report.
foreach ($this->collectedErrors as $error) {
parent::error($error['message'], $error['group'], $error['caller']);
}
}
}
/**
* Stores errors into an array.
*
* This test class is trying to verify that simpletest correctly sees errors
* and warnings. However, it can't generate errors and warnings that
* propagate up to the testing framework itself, or these tests would always
* fail. So, this special copy of error() doesn't propagate the errors up
* the class hierarchy. It just stuffs them into a protected collectedErrors
* array for various assertions to inspect.
*/
protected function error($message = '', $group = 'Other', array $caller = NULL) {
// Due to a WTF elsewhere, simpletest treats debug() and verbose()
// messages as if they were an 'error'. But, we don't want to collect
// those here. This function just wants to collect the real errors (PHP
// notices, PHP fatal errors, etc.), and let all the 'errors' from the
// 'User notice' group bubble up to the parent classes to be handled (and
// eventually displayed) as normal.
if ($group == 'User notice') {
parent::error($message, $group, $caller);
}
// Everything else should be collected but not propagated.
else {
$this->collectedErrors[] = [
'message' => $message,
'group' => $group,
'caller' => $caller
];
}
}
/**
* Asserts that a collected error matches what we are expecting.
*/
public function assertError($error, $group, $function, $file, $message = NULL) {
$this->assertEqual($error['group'], $group, format_string("Group was %group", ['%group' => $group]));
$this->assertEqual($error['caller']['function'], $function, format_string("Function was %function", ['%function' => $function]));
$this->assertEqual(drupal_basename($error['caller']['file']), $file, format_string("File was %file", ['%file' => $file]));
if (isset($message)) {
$this->assertEqual($error['message'], $message, format_string("Message was %message", ['%message' => $message]));
}
}
}
@@ -14,11 +14,15 @@ use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
@trigger_error(__NAMESPACE__ . '\EntityCacheTagsTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\EntityCacheTagsTestBase. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
/**
* Provides helper methods for Entity cache tags tests.
*
* @deprecated Scheduled for removal in Drupal 9.0.0.
* Use \Drupal\Tests\system\Functional\Entity\EntityCacheTagsTestBase instead.
*
* @see https://www.drupal.org/node/2946549
*/
abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
@@ -5,8 +5,15 @@ namespace Drupal\system\Tests\Entity;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\entity_test\FieldStorageDefinition;
@trigger_error(__NAMESPACE__ . '\EntityDefinitionTestTrait is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
/**
* Provides some test methods used to update existing entity definitions.
*
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0.
* Use \Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait.
*
* @see https://www.drupal.org/node/2946549
*/
trait EntityDefinitionTestTrait {
@@ -2,6 +2,8 @@
namespace Drupal\system\Tests\Entity;
@trigger_error(__FILE__ . ' is deprecated in Drupal 8.1.0 and will be removed before Drupal 9.0.0. Use \Drupal\KernelTests\Core\Entity\EntityKernelTestBase instead.', E_USER_DEPRECATED);
use Drupal\simpletest\KernelTestBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\user\Entity\Role;
@@ -10,7 +12,7 @@ use Drupal\user\Entity\User;
/**
* Defines an abstract test base for entity unit tests.
*
* @deprecated in Drupal 8.1.x, will be removed before Drupal 8.2.x. Use
* @deprecated in Drupal 8.1.0, will be removed before Drupal 9.0.0. Use
* \Drupal\KernelTests\Core\Entity\EntityKernelTestBase instead.
*/
abstract class EntityUnitTestBase extends KernelTestBase {
@@ -7,8 +7,15 @@ use Drupal\Core\Language\LanguageInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
@trigger_error(__NAMESPACE__ . '\EntityWithUriCacheTagsTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
/**
* Provides helper methods for Entity cache tags tests; for entities with URIs.
*
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0.
* Use \Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase.
*
* @see https://www.drupal.org/node/2946549
*/
abstract class EntityWithUriCacheTagsTestBase extends EntityCacheTagsTestBase {
@@ -163,7 +163,6 @@ class ElementsTableSelectTest extends WebTestBase {
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, 'Do not display a "Select all" checkbox when #multiple is FALSE, even when #js_select is TRUE.');
}
/**
* Test the whether the option checker gives an error on invalid tableselect values for checkboxes.
*/
@@ -187,7 +186,6 @@ class ElementsTableSelectTest extends WebTestBase {
}
/**
* Test the whether the option checker gives an error on invalid tableselect values for radios.
*/
@@ -211,7 +209,6 @@ class ElementsTableSelectTest extends WebTestBase {
$this->assertTrue(isset($errors['tableselect']), 'Option checker disallows invalid values for radio buttons.');
}
/**
* Helper function for the option check test to submit a form while collecting errors.
*
@@ -248,7 +245,7 @@ class ElementsTableSelectTest extends WebTestBase {
$errors = $form_state->getErrors();
// Clear errors and messages.
drupal_get_messages();
\Drupal::messenger()->deleteAll();
$form_state->clearErrors();
// Return the processed form together with form_state and errors
@@ -5,7 +5,7 @@ namespace Drupal\system\Tests\Image;
@trigger_error(__FILE__ . ' is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use Drupal\FunctionalTests\Image\ToolkitTestBase instead. See https://www.drupal.org/node/2862641.', E_USER_DEPRECATED);
use Drupal\simpletest\WebTestBase;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
/**
* Base class for image manipulation testing.
@@ -106,10 +106,10 @@ abstract class ToolkitTestBase extends WebTestBase {
// Determine if there were any expected that were not called.
$uncalled = array_diff($expected, $actual);
if (count($uncalled)) {
$this->assertTrue(FALSE, SafeMarkup::format('Expected operations %expected to be called but %uncalled was not called.', ['%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled)]));
$this->assertTrue(FALSE, new FormattableMarkup('Expected operations %expected to be called but %uncalled was not called.', ['%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled)]));
}
else {
$this->assertTrue(TRUE, SafeMarkup::format('All the expected operations were called: %expected', ['%expected' => implode(', ', $expected)]));
$this->assertTrue(TRUE, new FormattableMarkup('All the expected operations were called: %expected', ['%expected' => implode(', ', $expected)]));
}
// Determine if there were any unexpected calls.
@@ -117,7 +117,7 @@ abstract class ToolkitTestBase extends WebTestBase {
// count it as an error.
$unexpected = array_diff($actual, $expected);
if (count($unexpected) && (!in_array('apply', $expected) || count(array_intersect($unexpected, $operations)) !== count($unexpected))) {
$this->assertTrue(FALSE, SafeMarkup::format('Unexpected operations were called: %unexpected.', ['%unexpected' => implode(', ', $unexpected)]));
$this->assertTrue(FALSE, new FormattableMarkup('Unexpected operations were called: %unexpected.', ['%unexpected' => implode(', ', $unexpected)]));
}
else {
$this->assertTrue(TRUE, 'No unexpected operations were called.');
@@ -2,6 +2,8 @@
namespace Drupal\system\Tests\Installer;
@trigger_error(__NAMESPACE__ . '\ConfigAfterInstallerTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\FunctionalTests\Installer\ConfigAfterInstallerTestBase.', E_USER_DEPRECATED);
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Config\StorageInterface;
@@ -10,6 +12,9 @@ use Drupal\simpletest\InstallerTestBase;
/**
* Provides a class for install profiles to check their installed config.
*
* @deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0.
* Use \Drupal\FunctionalTests\Installer\ConfigAfterInstallerTestBase.
*/
abstract class ConfigAfterInstallerTestBase extends InstallerTestBase {
@@ -1,131 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\InstallerTestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests distribution profile support with existing settings.
*
* @group Installer
*/
class DistributionProfileExistingSettingsTest extends InstallerTestBase {
/**
* The distribution profile info.
*
* @var array
*/
protected $info;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => 'Distribution profile',
'distribution' => [
'name' => 'My Distribution',
'install' => [
'theme' => 'bartik',
],
],
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/mydistro';
mkdir($path, 0777, TRUE);
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
// Pre-configure hash salt.
// Any string is valid, so simply use the class name of this test.
$this->settings['settings']['hash_salt'] = (object) [
'value' => __CLASS__,
'required' => TRUE,
];
// Pre-configure database credentials.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
// Use the kernel to find the site path because the site.path service should
// not be available at this point in the install process.
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
// Pre-configure config directories.
$this->settings['config_directories'] = [
CONFIG_SYNC_DIRECTORY => (object) [
'value' => $site_path . '/files/config_staging',
'required' => TRUE,
],
];
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Make settings file not writable.
$filename = $this->siteDirectory . '/settings.php';
// Make the settings file read-only.
// Not using File API; a potential error must trigger a PHP warning.
chmod($filename, 0444);
// Verify that the distribution name appears.
$this->assertRaw($this->info['distribution']['name']);
// Verify that the requested theme is used.
$this->assertRaw($this->info['distribution']['install']['theme']);
// Verify that the "Choose profile" step does not appear.
$this->assertNoText('profile');
parent::setUpLanguage();
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a distribution profile.
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This step should not appear, since settings.php is fully configured
// already.
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getUsername());
// Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
$this->assertNull(Settings::get('install_profile'), 'The install profile has not been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
$this->rebuildContainer();
$this->pass('Container can be rebuilt even though distribution is not written to settings.php.');
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
}
}
@@ -1,81 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests distribution profile support.
*
* @group Installer
*/
class DistributionProfileTest extends InstallerTestBase {
/**
* The distribution profile info.
*
* @var array
*/
protected $info;
protected function setUp() {
$this->info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => 'Distribution profile',
'distribution' => [
'name' => 'My Distribution',
'install' => [
'theme' => 'bartik',
],
],
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/mydistro';
mkdir($path, 0777, TRUE);
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Verify that the distribution name appears.
$this->assertRaw($this->info['distribution']['name']);
// Verify that the distribution name is used in the site title.
$this->assertTitle('Choose language | ' . $this->info['distribution']['name']);
// Verify that the requested theme is used.
$this->assertRaw($this->info['distribution']['install']['theme']);
// Verify that the "Choose profile" step does not appear.
$this->assertNoText('profile');
parent::setUpLanguage();
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a distribution profile.
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getUsername());
// Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
$this->assertEqual(Settings::get('install_profile'), 'mydistro', 'The install profile has been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
}
}
@@ -1,142 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests distribution profile support with a 'langcode' query string.
*
* @group Installer
*
* @see \Drupal\system\Tests\Installer\DistributionProfileTranslationTest
*/
class DistributionProfileTranslationQueryTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected $langcode = 'de';
/**
* The distribution profile info.
*
* @var array
*/
protected $info;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => 'Distribution profile',
'distribution' => [
'name' => 'My Distribution',
'langcode' => $this->langcode,
'install' => [
'theme' => 'bartik',
],
],
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/mydistro';
mkdir($path, 0777, TRUE);
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.fr.po', $this->getPo('fr'));
// Pass a different language code than the one set in the distribution
// profile. This distribution language should still be used.
// The unrouted URL assembler does not exist at this point, so we build the
// URL ourselves.
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=fr');
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// This step is skipped, because the distribution profile uses a fixed
// language.
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a distribution profile.
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// The language should have been automatically detected, all following
// screens should be translated already.
$elements = $this->xpath('//input[@type="submit"]/@value');
$this->assertEqual((string) current($elements), 'Save and continue de');
$this->translations['Save and continue'] = 'Save and continue de';
// Check the language direction.
$direction = (string) current($this->xpath('/html/@dir'));
$this->assertEqual($direction, 'ltr');
// Verify that the distribution name appears.
$this->assertRaw($this->info['distribution']['name']);
// Verify that the requested theme is used.
$this->assertRaw($this->info['distribution']['install']['theme']);
// Verify that the "Choose profile" step does not appear.
$this->assertNoText('profile');
parent::setUpSettings();
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getDisplayName());
// Verify German was configured but not English.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
$this->assertNoText('English');
}
/**
* Returns the string for the test .po file.
*
* @param string $langcode
* The language code.
* @return string
* Contents for the test .po file.
*/
protected function getPo($langcode) {
return <<<ENDPO
msgid ""
msgstr ""
msgid "Save and continue"
msgstr "Save and continue $langcode"
ENDPO;
}
}
@@ -1,138 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests distribution profile support.
*
* @group Installer
*
* @see \Drupal\system\Tests\Installer\DistributionProfileTest
*/
class DistributionProfileTranslationTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected $langcode = 'de';
/**
* The distribution profile info.
*
* @var array
*/
protected $info;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => 'Distribution profile',
'distribution' => [
'name' => 'My Distribution',
'langcode' => $this->langcode,
'install' => [
'theme' => 'bartik',
],
],
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/mydistro';
mkdir($path, 0777, TRUE);
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
parent::visitInstaller();
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// This step is skipped, because the distribution profile uses a fixed
// language.
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a distribution profile.
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// The language should have been automatically detected, all following
// screens should be translated already.
$elements = $this->xpath('//input[@type="submit"]/@value');
$this->assertEqual((string) current($elements), 'Save and continue de');
$this->translations['Save and continue'] = 'Save and continue de';
// Check the language direction.
$direction = (string) current($this->xpath('/html/@dir'));
$this->assertEqual($direction, 'ltr');
// Verify that the distribution name appears.
$this->assertRaw($this->info['distribution']['name']);
// Verify that the requested theme is used.
$this->assertRaw($this->info['distribution']['install']['theme']);
// Verify that the "Choose profile" step does not appear.
$this->assertNoText('profile');
parent::setUpSettings();
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getDisplayName());
// Verify German was configured but not English.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
$this->assertNoText('English');
}
/**
* Returns the string for the test .po file.
*
* @param string $langcode
* The language code.
* @return string
* Contents for the test .po file.
*/
protected function getPo($langcode) {
return <<<ENDPO
msgid ""
msgstr ""
msgid "Save and continue"
msgstr "Save and continue $langcode"
ENDPO;
}
}
@@ -1,62 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Utility\Crypt;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer when a config_directory set up but does not exist.
*
* @group Installer
*/
class InstallerConfigDirectorySetNoDirectoryErrorTest extends InstallerTestBase {
/**
* The directory where the sync directory should be created during install.
*
* @var string
*/
protected $configDirectory;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->configDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64();
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
'value' => $this->configDirectory . '/sync',
'required' => TRUE,
];
// Create the files directory early so we can test the error case.
mkdir($this->publicFilesDirectory);
// Create a file so the directory can not be created.
file_put_contents($this->configDirectory, 'Test');
parent::setUp();
}
/**
* Installer step: Configure settings.
*/
protected function setUpSettings() {
// This step should not appear as we had a failure prior to the settings
// screen.
}
/**
* {@inheritdoc}
*/
protected function setUpSite() {
// This step should not appear as we had a failure prior to the settings
// screen.
}
/**
* Verifies that installation failed.
*/
public function testError() {
$this->assertText("An automated attempt to create the directory {$this->configDirectory}/sync failed, possibly due to a permissions problem.");
$this->assertFalse(file_exists($this->configDirectory . '/sync') && is_dir($this->configDirectory . '/sync'), "The directory {$this->configDirectory}/sync does not exist.");
}
}
@@ -1,49 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Utility\Crypt;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer when a config_directory set up but does not exist.
*
* @group Installer
*/
class InstallerConfigDirectorySetNoDirectoryTest extends InstallerTestBase {
/**
* The sync directory created during the install.
*
* @var string
*/
protected $syncDirectory;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->syncDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64() . '/sync';
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
'value' => $this->syncDirectory,
'required' => TRUE,
];
// Other directories will be created too.
$this->settings['config_directories']['custom'] = (object) [
'value' => $this->publicFilesDirectory . '/config_custom',
'required' => TRUE,
];
parent::setUp();
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertTrue(file_exists($this->syncDirectory) && is_dir($this->syncDirectory), "The directory {$this->syncDirectory} exists.");
$this->assertTrue(file_exists($this->publicFilesDirectory . '/config_custom') && is_dir($this->publicFilesDirectory . '/config_custom'), "The directory {$this->publicFilesDirectory}/custom_config exists.");
}
}
@@ -1,41 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Database\Database;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer with database errors.
*
* @group Installer
*/
class InstallerDatabaseErrorMessagesTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// We are creating a table here to force an error in the installer because
// it will try and create the drupal_install_test table as this is part of
// the standard database tests performed by the installer in
// Drupal\Core\Database\Install\Tasks.
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
parent::setUpSettings();
}
/**
* {@inheritdoc}
*/
protected function setUpSite() {
// This step should not appear as we had a failure on the settings screen.
}
/**
* Verifies that the error message in the settings step is correct.
*/
public function testSetUpSettingsErrorMessage() {
$this->assertRaw('<ul><li>Failed to <strong>CREATE</strong> a test table');
}
}
@@ -1,31 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer with empty settings file.
*
* @group Installer
*/
class InstallerEmptySettingsTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
// Create an empty settings.php file.
touch($this->siteDirectory . '/settings.php');
parent::setUp();
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
}
}
@@ -1,44 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer when a config_directory has already been set up.
*
* @group Installer
*/
class InstallerExistingConfigDirectoryTest extends InstallerTestBase {
/**
* The expected file perms of the folder.
*
* @var int
*/
protected $expectedFilePerms;
/**
* {@inheritdoc}
*/
protected function setUp() {
mkdir($this->siteDirectory . '/config_read_only', 0444);
$this->expectedFilePerms = fileperms($this->siteDirectory . '/config_read_only');
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
'value' => $this->siteDirectory . '/config_read_only',
'required' => TRUE,
];
parent::setUp();
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertEqual($this->expectedFilePerms, fileperms($this->siteDirectory . '/config_read_only'));
$this->assertEqual([], glob($this->siteDirectory . '/config_read_only/*'), 'The sync directory is empty after install because it is read-only.');
}
}
@@ -1,62 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
use Drupal\Core\Database\Database;
/**
* Tests the installer with an existing settings file with database connection
* info.
*
* @group Installer
*/
class InstallerExistingDatabaseSettingsTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
// Pre-configure database credentials in settings.php.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
parent::setUp();
}
/**
* {@inheritdoc}
*
* @todo The database settings form is not supposed to appear if settings.php
* contains a valid database connection already (but e.g. no config
* directories yet).
*/
protected function setUpSettings() {
// All database settings should be pre-configured, except password.
$values = $this->parameters['forms']['install_settings_form'];
$driver = $values['driver'];
$edit = [];
if (isset($values[$driver]['password']) && $values[$driver]['password'] !== '') {
$edit = $this->translatePostValues([
$driver => [
'password' => $values[$driver]['password'],
],
]);
}
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
}
}
@@ -1,40 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the installer with an existing Drupal installation.
*
* @group Installer
*/
class InstallerExistingInstallationTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
}
/**
* Verifies that Drupal can't be reinstalled while an existing installation is
* available.
*/
public function testInstaller() {
// Verify that Drupal can't be immediately reinstalled.
$this->visitInstaller();
$this->assertRaw('Drupal already installed');
// Delete settings.php and attempt to reinstall again.
unlink($this->siteDirectory . '/settings.php');
$this->visitInstaller();
$this->setUpLanguage();
$this->setUpProfile();
$this->setUpRequirementsProblem();
$this->setUpSettings();
$this->assertRaw('Drupal already installed');
}
}
@@ -1,108 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\DrupalKernel;
use Drupal\simpletest\InstallerTestBase;
use Drupal\Core\Database\Database;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests installer breaks with a profile mismatch and a read-only settings.php.
*
* @group Installer
*/
class InstallerExistingSettingsMismatchProfileBrokenTest extends InstallerTestBase {
/**
* {@inheritdoc}
*
* Configures a preexisting settings.php file without an install_profile
* setting before invoking the interactive installer.
*/
protected function setUp() {
// Pre-configure hash salt.
// Any string is valid, so simply use the class name of this test.
$this->settings['settings']['hash_salt'] = (object) [
'value' => __CLASS__,
'required' => TRUE,
];
// Pre-configure database credentials.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
// During interactive install we'll change this to a different profile and
// this test will ensure that the new value is written to settings.php.
$this->settings['settings']['install_profile'] = (object) [
'value' => 'minimal',
'required' => TRUE,
];
// Pre-configure config directories.
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
$this->settings['config_directories'] = [
CONFIG_SYNC_DIRECTORY => (object) [
'value' => $site_path . '/files/config_staging',
'required' => TRUE,
],
];
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
// Make settings file not writable. This will break the installer.
$filename = $this->siteDirectory . '/settings.php';
// Make the settings file read-only.
// Not using File API; a potential error must trigger a PHP warning.
chmod($filename, 0444);
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// This step is skipped, because there is a lagcode as a query param.
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a profile as a query param.
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This step should not appear, since settings.php is fully configured
// already.
}
protected function setUpSite() {
// This step should not appear, since settings.php could not be written.
}
/**
* Verifies that installation did not succeed.
*/
public function testBrokenInstaller() {
$this->assertTitle('Install profile mismatch | Drupal');
$this->assertText("The selected profile testing does not match the install_profile setting, which is minimal. Cannot write updated setting to {$this->siteDirectory}/settings.php.");
}
}
@@ -1,101 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\InstallerTestBase;
use Drupal\Core\Database\Database;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests the installer with an existing settings file but no install profile.
*
* @group Installer
*/
class InstallerExistingSettingsMismatchProfileTest extends InstallerTestBase {
/**
* {@inheritdoc}
*
* Configures a preexisting settings.php file without an install_profile
* setting before invoking the interactive installer.
*/
protected function setUp() {
// Pre-configure hash salt.
// Any string is valid, so simply use the class name of this test.
$this->settings['settings']['hash_salt'] = (object) [
'value' => __CLASS__,
'required' => TRUE,
];
// Pre-configure database credentials.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
// During interactive install we'll change this to a different profile and
// this test will ensure that the new value is written to settings.php.
$this->settings['settings']['install_profile'] = (object) [
'value' => 'minimal',
'required' => TRUE,
];
// Pre-configure config directories.
$this->settings['config_directories'] = [
CONFIG_SYNC_DIRECTORY => (object) [
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
'required' => TRUE,
],
];
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
// Provide profile and language in query string to skip these pages.
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// This step is skipped, because there is a lagcode as a query param.
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a profile as a query param.
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This step should not appear, since settings.php is fully configured
// already.
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertEqual('testing', \Drupal::installProfile());
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
}
}
@@ -1,70 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\DrupalKernel;
use Drupal\simpletest\InstallerTestBase;
use Drupal\Core\Database\Database;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests the installer with an existing settings file but no install profile.
*
* @group Installer
*/
class InstallerExistingSettingsNoProfileTest extends InstallerTestBase {
/**
* {@inheritdoc}
*
* Configures a preexisting settings.php file without an install_profile
* setting before invoking the interactive installer.
*/
protected function setUp() {
// Pre-configure hash salt.
// Any string is valid, so simply use the class name of this test.
$this->settings['settings']['hash_salt'] = (object) [
'value' => __CLASS__,
'required' => TRUE,
];
// Pre-configure database credentials.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
// Pre-configure config directories.
$this->settings['config_directories'] = [
CONFIG_SYNC_DIRECTORY => (object) [
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
'required' => TRUE,
],
];
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This step should not appear, since settings.php is fully configured
// already.
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertEqual('testing', \Drupal::installProfile());
}
}
@@ -1,82 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\InstallerTestBase;
use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests the installer with an existing settings file.
*
* @group Installer
*/
class InstallerExistingSettingsTest extends InstallerTestBase {
/**
* {@inheritdoc}
*
* Fully configures a preexisting settings.php file before invoking the
* interactive installer.
*/
protected function setUp() {
// Pre-configure hash salt.
// Any string is valid, so simply use the class name of this test.
$this->settings['settings']['hash_salt'] = (object) [
'value' => __CLASS__,
'required' => TRUE,
];
// During interactive install we'll change this to a different profile and
// this test will ensure that the new value is written to settings.php.
$this->settings['settings']['install_profile'] = (object) [
'value' => 'minimal',
'required' => TRUE,
];
// Pre-configure database credentials.
$connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
// Use the kernel to find the site path because the site.path service should
// not be available at this point in the install process.
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
// Pre-configure config directories.
$this->settings['config_directories'] = [
CONFIG_SYNC_DIRECTORY => (object) [
'value' => $site_path . '/files/config_sync',
'required' => TRUE,
],
];
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This step should not appear, since settings.php is fully configured
// already.
}
/**
* Verifies that installation succeeded.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertEqual('testing', \Drupal::installProfile(), 'Profile was changed from minimal to testing during interactive install.');
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
}
}
@@ -1,49 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Verifies that the early installer uses the correct language direction.
*
* @group Installer
*/
class InstallerLanguageDirectionTest extends InstallerTestBase {
/**
* Overrides the language code the installer should use.
*
* @var string
*/
protected $langcode = 'ar';
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.ar.po', "msgid \"\"\nmsgstr \"\"\nmsgid \"Save and continue\"\nmsgstr \"Save and continue Arabic\"");
parent::setUpLanguage();
// After selecting a different language than English, all following screens
// should be translated already.
$elements = $this->xpath('//input[@type="submit"]/@value');
$this->assertEqual((string) current($elements), 'Save and continue Arabic');
$this->translations['Save and continue'] = 'Save and continue Arabic';
// Verify that language direction is right-to-left.
$direction = (string) current($this->xpath('/html/@dir'));
$this->assertEqual($direction, 'rtl');
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
}
}
@@ -1,45 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Language\LanguageManager;
use Drupal\simpletest\InstallerTestBase;
/**
* Verifies that the installer language list combines local and remote languages.
*
* @group Installer
*/
class InstallerLanguagePageTest extends InstallerTestBase {
/**
* Installer step: Select language.
*/
protected function setUpLanguage() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
touch(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.xoxo.po');
// Check that all predefined languages show up with their native names.
$this->visitInstaller();
foreach (LanguageManager::getStandardLanguageList() as $langcode => $names) {
$this->assertOption('edit-langcode', $langcode);
$this->assertRaw('>' . $names[1] . '<');
}
// Check that our custom one shows up with the file name indicated language.
$this->assertOption('edit-langcode', 'xoxo');
$this->assertRaw('>xoxo<');
parent::setUpLanguage();
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
}
}
@@ -1,91 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests the interactive installer.
*
* @group Installer
*/
class InstallerTest extends InstallerTestBase {
/**
* Ensures that the user page is available after installation.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getUsername());
// Verify that the confirmation message appears.
require_once \Drupal::root() . '/core/includes/install.inc';
$this->assertRaw(t('Congratulations, you installed @drupal!', [
'@drupal' => drupal_install_profile_distribution_name(),
]));
// Ensure that the timezone is correct for sites under test after installing
// interactively.
$this->assertEqual($this->config('system.date')->get('timezone.default'), 'Australia/Sydney');
}
/**
* Installer step: Select language.
*/
protected function setUpLanguage() {
// Test that \Drupal\Core\Render\BareHtmlPageRenderer adds assets and
// metatags as expected to the first page of the installer.
$this->assertRaw('core/themes/seven/css/components/buttons.css');
$this->assertRaw('<meta charset="utf-8" />');
// Assert that the expected title is present.
$this->assertEqual('Choose language', $this->cssSelect('main h2')[0]);
parent::setUpLanguage();
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// Assert that the expected title is present.
$this->assertEqual('Select an installation profile', $this->cssSelect('main h2')[0]);
$result = $this->xpath('//span[contains(@class, :class) and contains(text(), :text)]', [':class' => 'visually-hidden', ':text' => 'Select an installation profile']);
$this->assertEqual(count($result), 1, "Title/Label not displayed when '#title_display' => 'invisible' attribute is set");
parent::setUpProfile();
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// Assert that the expected title is present.
$this->assertEqual('Database configuration', $this->cssSelect('main h2')[0]);
parent::setUpSettings();
}
/**
* {@inheritdoc}
*/
protected function setUpSite() {
// Assert that the expected title is present.
$this->assertEqual('Configure site', $this->cssSelect('main h2')[0]);
parent::setUpSite();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
parent::visitInstaller();
// Assert the title is correct and has the title suffix.
$this->assertTitle('Choose language | Drupal');
}
}
@@ -1,27 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
/**
* Tests translation files for multiple languages get imported during install.
*
* @group Installer
*/
class InstallerTranslationMultipleLanguageForeignTest extends InstallerTranslationMultipleLanguageTest {
/**
* Overrides the language code in which to install Drupal.
*
* @var string
*/
protected $langcode = 'de';
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
parent::setUpLanguage();
$this->translations['Save and continue'] = 'Save and continue de';
}
}
@@ -1,19 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
/**
* Tests that keeping English in a foreign language install works.
*
* @group Installer
*/
class InstallerTranslationMultipleLanguageKeepEnglishTest extends InstallerTranslationMultipleLanguageForeignTest {
/**
* Switch to the multilingual testing profile with English kept.
*
* @var string
*/
protected $profile = 'testing_multilingual_with_english';
}
@@ -1,178 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests translation files for multiple languages get imported during install.
*
* @group Installer
*/
class InstallerTranslationMultipleLanguageTest extends InstallerTestBase {
/**
* Switch to the multilingual testing profile.
*
* @var string
*/
protected $profile = 'testing_multilingual';
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Place custom local translations in the translations directory.
mkdir(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.es.po', $this->getPo('es'));
parent::setUpLanguage();
}
/**
* Returns the string for the test .po file.
*
* @param string $langcode
* The language code.
* @return string
* Contents for the test .po file.
*/
protected function getPo($langcode) {
return <<<ENDPO
msgid ""
msgstr ""
msgid "Save and continue"
msgstr "Save and continue $langcode"
msgid "Anonymous"
msgstr "Anonymous $langcode"
msgid "Language"
msgstr "Language $langcode"
#: Testing site name configuration during the installer.
msgid "Drupal"
msgstr "Drupal"
ENDPO;
}
/**
* {@inheritdoc}
*/
protected function installParameters() {
$params = parent::installParameters();
$params['forms']['install_configure_form']['site_name'] = 'SITE_NAME_' . $this->langcode;
return $params;
}
/**
* Tests that translations ended up at the expected places.
*/
public function testTranslationsLoaded() {
// Ensure the title is correct.
$this->assertEqual('SITE_NAME_' . $this->langcode, \Drupal::config('system.site')->get('name'));
// Verify German and Spanish were configured.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
$this->assertText('Spanish');
// If the installer was English or we used a profile that keeps English, we
// expect that configured also. Otherwise English should not be configured
// on the site.
if ($this->langcode == 'en' || $this->profile == 'testing_multilingual_with_english') {
$this->assertText('English');
}
else {
$this->assertNoText('English');
}
// Verify the strings from the translation files were imported.
$this->verifyImportedStringsTranslated();
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
$language_manager = \Drupal::languageManager();
// If the site was installed in a foreign language (only tested with German
// in subclasses), then the active configuration should be updated and no
// override should exist in German. Otherwise the German translation should
// end up in overrides the same way as Spanish (which is not used as a site
// installation language). English should be available based on profile
// information and should be possible to add if not yet added, making
// English overrides available.
$config = \Drupal::config('user.settings');
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
$override_es = $language_manager->getLanguageConfigOverride('es', 'user.settings');
if ($this->langcode == 'de') {
// Active configuration should be in German and no German override should
// exist.
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
$this->assertEqual($config->get('langcode'), 'de');
$this->assertTrue($override_de->isNew());
if ($this->profile == 'testing_multilingual_with_english') {
// English is already added in this profile. Should make the override
// available.
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
}
else {
// English is not yet available.
$this->assertTrue($override_en->isNew());
// Adding English should make the English override available.
$edit = ['predefined_langcode' => 'en'];
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
}
// Activate a module, to make sure that config is not overridden by module
// installation.
$edit = [
'modules[views][enable]' => TRUE,
'modules[filter][enable]' => TRUE,
];
$this->drupalPostForm('admin/modules', $edit, t('Install'));
// Verify the strings from the translation are still as expected.
$this->verifyImportedStringsTranslated();
}
else {
// Active configuration should be English.
$this->assertEqual($config->get('anonymous'), 'Anonymous');
$this->assertEqual($config->get('langcode'), 'en');
// There should not be an English override.
$this->assertTrue($override_en->isNew());
// German should be an override.
$this->assertEqual($override_de->get('anonymous'), 'Anonymous de');
}
// Spanish is always an override (never used as installation language).
$this->assertEqual($override_es->get('anonymous'), 'Anonymous es');
}
/**
* Helper function to verify that the expected strings are translated.
*/
protected function verifyImportedStringsTranslated() {
$test_samples = ['Save and continue', 'Anonymous', 'Language'];
$langcodes = ['de', 'es'];
foreach ($test_samples as $sample) {
foreach ($langcodes as $langcode) {
$edit = [];
$edit['langcode'] = $langcode;
$edit['translation'] = 'translated';
$edit['string'] = $sample;
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
$this->assertText($sample . ' ' . $langcode);
}
}
}
}
@@ -1,85 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\InstallerTestBase;
/**
* Installs Drupal in German and checks resulting site.
*
* @group Installer
*
* @see \Drupal\system\Tests\Installer\InstallerTranslationTest
*/
class InstallerTranslationQueryTest extends InstallerTestBase {
/**
* Overrides the language code in which to install Drupal.
*
* @var string
*/
protected $langcode = 'de';
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
// The unrouted URL assembler does not exist at this point, so we build the
// URL ourselves.
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=' . $this->langcode);
// The language should have been automatically detected, all following
// screens should be translated already.
$elements = $this->xpath('//input[@type="submit"]/@value');
$this->assertEqual((string) current($elements), 'Save and continue de');
$this->translations['Save and continue'] = 'Save and continue de';
// Check the language direction.
$direction = (string) current($this->xpath('/html/@dir'));
$this->assertEqual($direction, 'ltr');
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// The language was was preset by passing a query parameter in the URL, so
// no explicit language selection is necessary.
}
/**
* Verifies the expected behaviors of the installation result.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Verify German was configured but not English.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
$this->assertNoText('English');
}
/**
* Returns the string for the test .po file.
*
* @param string $langcode
* The language code.
* @return string
* Contents for the test .po file.
*/
protected function getPo($langcode) {
return <<<ENDPO
msgid ""
msgstr ""
msgid "Save and continue"
msgstr "Save and continue $langcode"
ENDPO;
}
}
@@ -1,155 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Database\Database;
use Drupal\simpletest\InstallerTestBase;
use Drupal\user\Entity\User;
/**
* Installs Drupal in German and checks resulting site.
*
* @group Installer
*/
class InstallerTranslationTest extends InstallerTestBase {
/**
* Overrides the language code in which to install Drupal.
*
* @var string
*/
protected $langcode = 'de';
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Place a custom local translation in the translations directory.
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
parent::setUpLanguage();
// After selecting a different language than English, all following screens
// should be translated already.
$elements = $this->xpath('//input[@type="submit"]/@value');
$this->assertEqual((string) current($elements), 'Save and continue de');
$this->translations['Save and continue'] = 'Save and continue de';
// Check the language direction.
$direction = (string) current($this->xpath('/html/@dir'));
$this->assertEqual($direction, 'ltr');
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// We are creating a table here to force an error in the installer because
// it will try and create the drupal_install_test table as this is part of
// the standard database tests performed by the installer in
// Drupal\Core\Database\Install\Tasks.
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
parent::setUpSettings();
// Ensure that the error message translation is working.
$this->assertRaw('Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter.');
$this->assertRaw('<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl <em class="placeholder">CREATE TABLE {drupal_install_test} (id int NULL)</em> fehlgeschlagen.');
// Now do it successfully.
Database::getConnection('default')->query('DROP TABLE {drupal_install_test}');
parent::setUpSettings();
}
/**
* Verifies the expected behaviors of the installation result.
*/
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Verify German was configured but not English.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
$this->assertNoText('English');
// The current container still has the english as current language, rebuild.
$this->rebuildContainer();
/** @var \Drupal\user\Entity\User $account */
$account = User::load(0);
$this->assertEqual($account->language()->getId(), 'en', 'Anonymous user is English.');
$account = User::load(1);
$this->assertEqual($account->language()->getId(), 'en', 'Administrator user is English.');
$account = $this->drupalCreateUser();
$this->assertEqual($account->language()->getId(), 'de', 'New user is German.');
// Ensure that we can enable basic_auth on a non-english site.
$this->drupalPostForm('admin/modules', ['modules[basic_auth][enable]' => TRUE], t('Install'));
$this->assertResponse(200);
// Assert that the theme CSS was added to the page.
$edit = ['preprocess_css' => FALSE];
$this->drupalPostForm('admin/config/development/performance', $edit, t('Save configuration'));
$this->drupalGet('<front>');
$this->assertRaw('classy/css/components/action-links.css');
// Verify the strings from the translation files were imported.
$test_samples = ['Save and continue', 'Anonymous'];
foreach ($test_samples as $sample) {
$edit = [];
$edit['langcode'] = 'de';
$edit['translation'] = 'translated';
$edit['string'] = $sample;
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
$this->assertText($sample . ' de');
}
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
$language_manager = \Drupal::languageManager();
// Installed in German, configuration should be in German. No German or
// English overrides should be present.
$config = \Drupal::config('user.settings');
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
$this->assertEqual($config->get('langcode'), 'de');
$this->assertTrue($override_de->isNew());
$this->assertTrue($override_en->isNew());
// Assert that adding English makes the English override available.
$edit = ['predefined_langcode' => 'en'];
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
$this->assertFalse($override_en->isNew());
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
}
/**
* Returns the string for the test .po file.
*
* @param string $langcode
* The language code.
* @return string
* Contents for the test .po file.
*/
protected function getPo($langcode) {
return <<<ENDPO
msgid ""
msgstr ""
msgid "Save and continue"
msgstr "Save and continue $langcode"
msgid "Anonymous"
msgstr "Anonymous $langcode"
msgid "Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider."
msgstr "Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter."
msgid "Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>"
msgstr "<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl %query fehlgeschlagen."
ENDPO;
}
}
@@ -1,28 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\KernelTests\AssertConfigTrait;
/**
* Tests the interactive installer installing the minimal profile.
*
* @group Installer
*/
class MinimalInstallerTest extends ConfigAfterInstallerTestBase {
use AssertConfigTrait;
/**
* {@inheritdoc}
*/
protected $profile = 'minimal';
/**
* Ensures that the exported minimal configuration is up to date.
*/
public function testMinimalConfig() {
$this->assertInstalledConfig([]);
}
}
@@ -1,91 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests multiple distribution profile support.
*
* @group Installer
*/
class MultipleDistributionsProfileTest extends InstallerTestBase {
/**
* The distribution profile info.
*
* @var array
*/
protected $info;
/**
* {@inheritdoc}
*/
protected function setUp() {
// Create two distributions.
foreach (['distribution_one', 'distribution_two'] as $name) {
$info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => $name . ' profile',
'distribution' => [
'name' => $name,
'install' => [
'theme' => 'bartik',
],
],
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/' . $name;
mkdir($path, 0777, TRUE);
file_put_contents("$path/$name.info.yml", Yaml::encode($info));
}
// Install the first distribution.
$this->profile = 'distribution_one';
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpLanguage() {
// Verify that the distribution name appears.
$this->assertRaw('distribution_one');
// Verify that the requested theme is used.
$this->assertRaw('bartik');
// Verify that the "Choose profile" step does not appear.
$this->assertNoText('profile');
parent::setUpLanguage();
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is a distribution profile.
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getUsername());
// Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
$this->assertEqual(Settings::get('install_profile'), 'distribution_one', 'The install profile has been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'distribution_one', 'The install profile has been written to core.extension configuration.');
$this->rebuildContainer();
$this->pass('Container can be rebuilt as distribution is written to configuration.');
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
}
}
@@ -1,60 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**
* Tests distribution profile support.
*
* @group Installer
*/
class SingleVisibleProfileTest extends InstallerTestBase {
/**
* The installation profile to install.
*
* Not needed when only one is visible.
*
* @var string
*/
protected $profile = NULL;
protected function setUp() {
$profiles = ['standard', 'demo_umami'];
foreach ($profiles as $profile) {
$info = [
'type' => 'profile',
'core' => \Drupal::CORE_COMPATIBILITY,
'name' => 'Override ' . $profile,
'hidden' => TRUE,
];
// File API functions are not available yet.
$path = $this->siteDirectory . '/profiles/' . $profile;
mkdir($path, 0777, TRUE);
file_put_contents("$path/$profile.info.yml", Yaml::encode($info));
}
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpProfile() {
// This step is skipped, because there is only one visible profile.
}
/**
* Confirms that the installation succeeded.
*/
public function testInstalled() {
$this->assertUrl('user/1');
$this->assertResponse(200);
// Confirm that we are logged-in after installation.
$this->assertText($this->rootUser->getUsername());
// Confirm that the minimal profile was installed.
$this->assertEqual(drupal_get_profile(), 'minimal');
}
}
@@ -1,39 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\WebTestBase;
/**
* Tests that the site name can be set during a non-interactive installation.
*
* @group Installer
*/
class SiteNameTest extends WebTestBase {
/**
* The site name to be used when testing.
*
* @var string
*/
protected $siteName;
/**
* {@inheritdoc}
*/
protected function installParameters() {
$this->siteName = $this->randomMachineName();
$parameters = parent::installParameters();
$parameters['forms']['install_configure_form']['site_name'] = $this->siteName;
return $parameters;
}
/**
* Tests that the desired site name appears on the page after installation.
*/
public function testSiteName() {
$this->drupalGet('');
$this->assertRaw($this->siteName, 'The site name that was set during the installation appears on the front page after installation.');
}
}
@@ -1,68 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
/**
* Tests the interactive installer installing the standard profile.
*
* @group Installer
*/
class StandardInstallerTest extends ConfigAfterInstallerTestBase {
/**
* {@inheritdoc}
*/
protected $profile = 'standard';
/**
* Ensures that the user page is available after installation.
*/
public function testInstaller() {
// Verify that the Standard install profile's default frontpage appears.
$this->assertRaw('No front page content has been created yet.');
}
/**
* {@inheritdoc}
*/
protected function setUpSite() {
// Test that the correct theme is being used.
$this->assertNoRaw('bartik');
$this->assertRaw('themes/seven/css/theme/install-page.css');
parent::setUpSite();
}
/**
* {@inheritdoc}
*/
protected function curlExec($curl_options, $redirect = FALSE) {
// Ensure that we see the classy progress CSS on the batch page.
// Batch processing happens as part of HTTP redirects, so we can access the
// HTML of the batch page.
if (strpos($curl_options[CURLOPT_URL], '&id=1&op=do_nojs') !== FALSE) {
$this->assertRaw('themes/classy/css/components/progress.css');
}
return parent::curlExec($curl_options, $redirect);
}
/**
* Ensures that the exported standard configuration is up to date.
*/
public function testStandardConfig() {
$skipped_config = [];
// \Drupal\simpletest\WebTestBase::installParameters() uses
// simpletest@example.com as mail address.
$skipped_config['contact.form.feedback'][] = '- simpletest@example.com';
// \Drupal\filter\Entity\FilterFormat::toArray() drops the roles of filter
// formats.
$skipped_config['filter.format.basic_html'][] = 'roles:';
$skipped_config['filter.format.basic_html'][] = '- authenticated';
$skipped_config['filter.format.full_html'][] = 'roles:';
$skipped_config['filter.format.full_html'][] = '- administrator';
$skipped_config['filter.format.restricted_html'][] = 'roles:';
$skipped_config['filter.format.restricted_html'][] = '- anonymous';
$this->assertInstalledConfig($skipped_config);
}
}
@@ -59,8 +59,9 @@ abstract class ModuleTestBase extends WebTestBase {
public function assertModuleTablesExist($module) {
$tables = array_keys(drupal_get_module_schema($module));
$tables_exist = TRUE;
$schema = Database::getConnection()->schema();
foreach ($tables as $table) {
if (!db_table_exists($table)) {
if (!$schema->tableExists($table)) {
$tables_exist = FALSE;
}
}
@@ -76,8 +77,9 @@ abstract class ModuleTestBase extends WebTestBase {
public function assertModuleTablesDoNotExist($module) {
$tables = array_keys(drupal_get_module_schema($module));
$tables_exist = FALSE;
$schema = Database::getConnection()->schema();
foreach ($tables as $table) {
if (db_table_exists($table)) {
if ($schema->tableExists($table)) {
$tables_exist = TRUE;
}
}
@@ -51,27 +51,26 @@ class UrlAliasFixtures {
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_en',
'langcode' => 'en'
'langcode' => 'en',
],
[
'source' => '/node/2',
'alias' => '/alias_for_node_2_en',
'langcode' => 'en'
'langcode' => 'en',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_fr',
'langcode' => 'fr'
'langcode' => 'fr',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_und',
'langcode' => 'und'
]
'langcode' => 'und',
],
];
}
/**
* Returns the table definition for the URL alias fixtures.
*
@@ -57,7 +57,7 @@ class SessionTest extends WebTestBase {
// session_test_user_login() which breaks a normal assertion.
$edit = [
'name' => $user->getUsername(),
'pass' => $user->pass_raw
'pass' => $user->pass_raw,
];
$this->drupalPostForm('user/login', $edit, t('Log in'));
$this->drupalGet('user');
@@ -2,6 +2,8 @@
namespace Drupal\system\Tests\System;
@trigger_error('\Drupal\system\Tests\System\SystemConfigFormTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use \Drupal\KernelTests\ConfigFormTestBase instead.', E_USER_DEPRECATED);
use Drupal\Core\Form\FormState;
use Drupal\simpletest\WebTestBase;
@@ -10,12 +12,17 @@ use Drupal\simpletest\WebTestBase;
*
* @see UserAdminSettingsFormTest
* For a full working implementation.
*
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Use
* \Drupal\KernelTests\ConfigFormTestBase instead.
*
* @see https://www.drupal.org/node/2941907
*/
abstract class SystemConfigFormTestBase extends WebTestBase {
/**
* Form ID to use for testing.
*
* @var \Drupal\Core\Form\FormInterface.
* @var \Drupal\Core\Form\FormInterface
*/
protected $form;
@@ -1,283 +0,0 @@
<?php
namespace Drupal\system\Tests\System;
use Drupal\simpletest\WebTestBase;
/**
* Tests kernel panic when things are really messed up.
*
* @group system
*/
class UncaughtExceptionTest extends WebTestBase {
/**
* Exceptions thrown by site under test that contain this text are ignored.
*
* @var string
*/
protected $expectedExceptionMessage;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['error_service_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\ninclude_once 'core/modules/system/src/Tests/Bootstrap/ErrorContainer.php';\n";
$settings_php .= "\ninclude_once 'core/modules/system/src/Tests/Bootstrap/ExceptionContainer.php';\n";
file_put_contents($settings_filename, $settings_php);
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_DISPLAY_VERBOSE,
'required' => TRUE,
];
$this->writeSettings($settings);
}
/**
* Tests uncaught exception handling when system is in a bad state.
*/
public function testUncaughtException() {
$this->expectedExceptionMessage = 'Oh oh, bananas in the instruments.';
\Drupal::state()->set('error_service_test.break_bare_html_renderer', TRUE);
$this->config('system.logging')
->set('error_level', ERROR_REPORTING_HIDE)
->save();
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_HIDE,
'required' => TRUE,
];
$this->writeSettings($settings);
$this->drupalGet('');
$this->assertResponse(500);
$this->assertText('The website encountered an unexpected error. Please try again later.');
$this->assertNoText($this->expectedExceptionMessage);
$this->config('system.logging')
->set('error_level', ERROR_REPORTING_DISPLAY_ALL)
->save();
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_DISPLAY_ALL,
'required' => TRUE,
];
$this->writeSettings($settings);
$this->drupalGet('');
$this->assertResponse(500);
$this->assertText('The website encountered an unexpected error. Please try again later.');
$this->assertText($this->expectedExceptionMessage);
$this->assertErrorLogged($this->expectedExceptionMessage);
}
/**
* Tests uncaught exception handling with custom exception handler.
*/
public function testUncaughtExceptionCustomExceptionHandler() {
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\n";
$settings_php .= "set_exception_handler(function() {\n";
$settings_php .= " header('HTTP/1.1 418 I\'m a teapot');\n";
$settings_php .= " print('Oh oh, flying teapots');\n";
$settings_php .= "});\n";
file_put_contents($settings_filename, $settings_php);
\Drupal::state()->set('error_service_test.break_bare_html_renderer', TRUE);
$this->drupalGet('');
$this->assertResponse(418);
$this->assertNoText('The website encountered an unexpected error. Please try again later.');
$this->assertNoText('Oh oh, bananas in the instruments');
$this->assertText('Oh oh, flying teapots');
}
/**
* Tests a missing dependency on a service.
*/
public function testMissingDependency() {
if (version_compare(PHP_VERSION, '7.1') < 0) {
$this->expectedExceptionMessage = 'Argument 1 passed to Drupal\error_service_test\LonelyMonkeyClass::__construct() must be an instance of Drupal\Core\Database\Connection, non';
}
else {
$this->expectedExceptionMessage = 'Too few arguments to function Drupal\error_service_test\LonelyMonkeyClass::__construct(), 0 passed';
}
$this->drupalGet('broken-service-class');
$this->assertResponse(500);
$this->assertRaw('The website encountered an unexpected error.');
$this->assertRaw($this->expectedExceptionMessage);
$this->assertErrorLogged($this->expectedExceptionMessage);
}
/**
* Tests a missing dependency on a service with a custom error handler.
*/
public function testMissingDependencyCustomErrorHandler() {
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\n";
$settings_php .= "set_error_handler(function() {\n";
$settings_php .= " header('HTTP/1.1 418 I\'m a teapot');\n";
$settings_php .= " print('Oh oh, flying teapots');\n";
$settings_php .= " exit();\n";
$settings_php .= "});\n";
$settings_php .= "\$settings['teapots'] = TRUE;\n";
file_put_contents($settings_filename, $settings_php);
$this->drupalGet('broken-service-class');
$this->assertResponse(418);
$this->assertRaw('Oh oh, flying teapots');
$message = 'Argument 1 passed to Drupal\error_service_test\LonelyMonkeyClass::__construct() must be an instance of Drupal\Core\Database\Connection, non';
$this->assertNoRaw('The website encountered an unexpected error.');
$this->assertNoRaw($message);
$found_exception = FALSE;
foreach ($this->assertions as &$assertion) {
if (strpos($assertion['message'], $message) !== FALSE) {
$found_exception = TRUE;
$this->deleteAssert($assertion['message_id']);
unset($assertion);
}
}
$this->assertTrue($found_exception, 'Ensure that the exception of a missing constructor argument was triggered.');
}
/**
* Tests a container which has an error.
*/
public function testErrorContainer() {
$settings = [];
$settings['settings']['container_base_class'] = (object) [
'value' => '\Drupal\system\Tests\Bootstrap\ErrorContainer',
'required' => TRUE,
];
$this->writeSettings($settings);
\Drupal::service('kernel')->invalidateContainer();
$this->expectedExceptionMessage = 'Argument 1 passed to Drupal\system\Tests\Bootstrap\ErrorContainer::Drupal\system\Tests\Bootstrap\{closur';
$this->drupalGet('');
$this->assertResponse(500);
$this->assertRaw($this->expectedExceptionMessage);
$this->assertErrorLogged($this->expectedExceptionMessage);
}
/**
* Tests a container which has an exception really early.
*/
public function testExceptionContainer() {
$settings = [];
$settings['settings']['container_base_class'] = (object) [
'value' => '\Drupal\system\Tests\Bootstrap\ExceptionContainer',
'required' => TRUE,
];
$this->writeSettings($settings);
\Drupal::service('kernel')->invalidateContainer();
$this->expectedExceptionMessage = 'Thrown exception during Container::get';
$this->drupalGet('');
$this->assertResponse(500);
$this->assertRaw('The website encountered an unexpected error');
$this->assertRaw($this->expectedExceptionMessage);
$this->assertErrorLogged($this->expectedExceptionMessage);
}
/**
* Tests the case when the database connection is gone.
*/
public function testLostDatabaseConnection() {
$incorrect_username = $this->randomMachineName(16);
switch ($this->container->get('database')->driver()) {
case 'pgsql':
case 'mysql':
$this->expectedExceptionMessage = $incorrect_username;
break;
default:
// We can not carry out this test.
$this->pass('Unable to run \Drupal\system\Tests\System\UncaughtExceptionTest::testLostDatabaseConnection for this database type.');
return;
}
// We simulate a broken database connection by rewrite settings.php to no
// longer have the proper data.
$settings['databases']['default']['default']['username'] = (object) [
'value' => $incorrect_username,
'required' => TRUE,
];
$settings['databases']['default']['default']['password'] = (object) [
'value' => $this->randomMachineName(16),
'required' => TRUE,
];
$this->writeSettings($settings);
$this->drupalGet('');
$this->assertResponse(500);
$this->assertRaw('DatabaseAccessDeniedException');
$this->assertErrorLogged($this->expectedExceptionMessage);
}
/**
* Tests fallback to PHP error log when an exception is thrown while logging.
*/
public function testLoggerException() {
// Ensure the test error log is empty before these tests.
$this->assertNoErrorsLogged();
$this->expectedExceptionMessage = 'Deforestation';
\Drupal::state()->set('error_service_test.break_logger', TRUE);
$this->drupalGet('');
$this->assertResponse(500);
$this->assertText('The website encountered an unexpected error. Please try again later.');
$this->assertRaw($this->expectedExceptionMessage);
// Find fatal error logged to the simpletest error.log
$errors = file(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
$this->assertIdentical(count($errors), 8, 'The error + the error that the logging service is broken has been written to the error log.');
$this->assertTrue(strpos($errors[0], 'Failed to log error') !== FALSE, 'The error handling logs when an error could not be logged to the logger.');
$expected_path = \Drupal::root() . '/core/modules/system/tests/modules/error_service_test/src/MonkeysInTheControlRoom.php';
$expected_line = 59;
$expected_entry = "Failed to log error: Exception: Deforestation in Drupal\\error_service_test\\MonkeysInTheControlRoom->handle() (line ${expected_line} of ${expected_path})";
$this->assert(strpos($errors[0], $expected_entry) !== FALSE, 'Original error logged to the PHP error log when an exception is thrown by a logger');
// The exception is expected. Do not interpret it as a test failure. Not
// using File API; a potential error must trigger a PHP warning.
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
}
/**
* {@inheritdoc}
*/
protected function error($message = '', $group = 'Other', array $caller = NULL) {
if (!empty($this->expectedExceptionMessage) && strpos($message, $this->expectedExceptionMessage) !== FALSE) {
// We're expecting this error.
return FALSE;
}
return parent::error($message, $group, $caller);
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ function hook_system_themes_page_alter(&$theme_groups) {
$theme->operations[] = [
'title' => t('Foo'),
'url' => Url::fromRoute('system.themes_page'),
'query' => ['theme' => $theme->getName()]
'query' => ['theme' => $theme->getName()],
];
}
}
+45 -7
View File
@@ -51,10 +51,10 @@ function system_requirements($phase) {
'value' => t('%profile_name (%profile-%version)', [
'%profile_name' => $info['name'],
'%profile' => $profile,
'%version' => $info['version']
'%version' => $info['version'],
]),
'severity' => REQUIREMENT_INFO,
'weight' => -9
'weight' => -9,
];
}
@@ -77,14 +77,15 @@ function system_requirements($phase) {
}
// Web server information.
$software = \Drupal::request()->server->get('SERVER_SOFTWARE');
$request_object = \Drupal::request();
$software = $request_object->server->get('SERVER_SOFTWARE');
$requirements['webserver'] = [
'title' => t('Web server'),
'value' => $software,
];
// Tests clean URL support.
if ($phase == 'install' && $install_state['interactive'] && !isset($_GET['rewrite']) && strpos($software, 'Apache') !== FALSE) {
if ($phase == 'install' && $install_state['interactive'] && !$request_object->query->has('rewrite') && strpos($software, 'Apache') !== FALSE) {
// If the Apache rewrite module is not enabled, Apache version must be >=
// 2.2.16 because of the FallbackResource directive in the root .htaccess
// file. Since the Apache version reported by the server is dependent on the
@@ -435,12 +436,13 @@ function system_requirements($phase) {
// directory. This allows additional files in the site directory to be
// updated when they are managed in a version control system.
if (Settings::get('skip_permissions_hardening')) {
$conf_errors[] = t('Protection disabled');
$error_value = t('Protection disabled');
// If permissions hardening is disabled, then only show a warning for a
// writable file, as a reminder, rather than an error.
$file_protection_severity = REQUIREMENT_WARNING;
}
else {
$error_value = t('Not protected');
// In normal operation, writable files or directories are an error.
$file_protection_severity = REQUIREMENT_ERROR;
if (!drupal_verify_install_file($site_path, FILE_NOT_WRITABLE, 'dir')) {
@@ -449,7 +451,7 @@ function system_requirements($phase) {
}
foreach (['settings.php', 'settings.local.php', 'services.yml'] as $conf_file) {
$full_path = $site_path . '/' . $conf_file;
if (file_exists($full_path) && (Settings::get('skip_permissions_hardening') || !drupal_verify_install_file($full_path, FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE))) {
if (file_exists($full_path) && !drupal_verify_install_file($full_path, FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE, 'file', !Settings::get('skip_permissions_hardening'))) {
$conf_errors[] = t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", ['%file' => $full_path]);
}
}
@@ -471,7 +473,7 @@ function system_requirements($phase) {
];
}
$requirements['configuration_files'] = [
'value' => t('Not protected'),
'value' => $error_value,
'severity' => $file_protection_severity,
'description' => $description,
];
@@ -1000,6 +1002,34 @@ function system_requirements($phase) {
];
}
// During installs from configuration don't support install profiles that
// implement hook_install.
if ($phase == 'install' && !empty($install_state['config_install_path'])) {
$install_hook = $install_state['parameters']['profile'] . '_install';
if (function_exists($install_hook)) {
$requirements['config_install'] = [
'title' => t('Configuration install'),
'value' => $install_state['parameters']['profile'],
'description' => t('The selected profile has a hook_install() implementation and therefore can not be installed from configuration.'),
'severity' => REQUIREMENT_ERROR,
];
}
}
if ($phase === 'runtime') {
$settings = Settings::getAll();
if (array_key_exists('install_profile', $settings)) {
// The following message is only informational because not all site owners
// have access to edit their settings.php as it may be controlled by their
// hosting provider.
$requirements['install_profile_in_settings'] = [
'title' => t('Install profile in settings'),
'value' => t("Drupal 8 no longer uses the \$settings['install_profile'] value in settings.php and it can be removed."),
'severity' => REQUIREMENT_INFO,
];
}
}
return $requirements;
}
@@ -1836,6 +1866,10 @@ function system_update_8200(&$sandbox) {
*/
function system_update_8201() {
// Empty update to cause a cache rebuild.
// Use hook_post_update_NAME() instead to clear the cache.
// The use of hook_update_N() to clear the cache has been deprecated
// see https://www.drupal.org/node/2960601 for more details.
}
/**
@@ -1843,6 +1877,10 @@ function system_update_8201() {
*/
function system_update_8202() {
// Empty update to cause a cache rebuild.
// Use hook_post_update_NAME() instead to clear the cache.The use
// of hook_update_N to clear the cache has been deprecated see
// https://www.drupal.org/node/2960601 for more details.
}
/**
+51 -138
View File
@@ -9,10 +9,10 @@ use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Extension\Exception\UnknownExtensionException;
use Drupal\Core\Queue\QueueGarbageCollectionInterface;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory;
use Drupal\Core\PageCache\RequestPolicyInterface;
@@ -767,10 +767,10 @@ function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
}
// Provide the page with information about the individual asset libraries
// used, information not otherwise available when aggregation is enabled.
$minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_merge(
$minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_unique(array_merge(
$assets->getLibraries(),
$assets->getAlreadyLoadedLibraries()
));
)));
sort($minimal_libraries);
$settings['ajaxPageState']['libraries'] = implode(',', $minimal_libraries);
}
@@ -835,7 +835,13 @@ function system_user_login(UserInterface $account) {
$config = \Drupal::config('system.date');
// If the user has a NULL time zone, notify them to set a time zone.
if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
drupal_set_message(t('Configure your <a href=":user-edit">account time zone setting</a>.', [':user-edit' => $account->url('edit-form', ['query' => \Drupal::destination()->getAsArray(), 'fragment' => 'edit-timezone'])]));
\Drupal::messenger()
->addStatus(t('Configure your <a href=":user-edit">account time zone setting</a>.', [
':user-edit' => $account->url('edit-form', [
'query' => \Drupal::destination()->getAsArray(),
'fragment' => 'edit-timezone',
]),
]));
}
}
@@ -913,7 +919,7 @@ function system_check_directory($form_element, FormStateInterface $form_state) {
$logger = \Drupal::logger('file system');
if (!is_dir($directory) && !drupal_mkdir($directory, NULL, TRUE)) {
// If the directory does not exists and cannot be created.
// If the directory does not exist and cannot be created.
$form_state->setErrorByName($form_element['#parents'][0], t('The directory %directory does not exist and could not be created.', ['%directory' => $directory]));
$logger->error('The directory %directory does not exist and could not be created.', ['%directory' => $directory]);
}
@@ -961,27 +967,22 @@ function system_check_directory($form_element, FormStateInterface $form_state) {
*/
function system_get_info($type, $name = NULL) {
if ($type == 'module') {
$info = &drupal_static(__FUNCTION__);
if (!isset($info)) {
if ($cache = \Drupal::cache()->get('system.module.info')) {
$info = $cache->data;
/** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
$module_list = \Drupal::service('extension.list.module');
if (isset($name)) {
try {
return $module_list->getExtensionInfo($name);
}
else {
$data = system_rebuild_module_data();
foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) {
if (isset($data[$module])) {
$info[$module] = $data[$module]->info;
}
}
// Store the module information in cache. This cache is cleared by
// calling system_rebuild_module_data(), for example, when listing
// modules, (un)installing modules, importing configuration, updating
// the site and when flushing all the caches.
\Drupal::cache()->set('system.module.info', $info);
catch (UnknownExtensionException $e) {
return [];
}
}
else {
return $module_list->getAllInstalledInfo();
}
}
else {
// @todo move into ThemeExtensionList https://www.drupal.org/node/2659940
$info = [];
$list = system_list($type);
foreach ($list as $shortname => $item) {
@@ -989,96 +990,11 @@ function system_get_info($type, $name = NULL) {
$info[$shortname] = $item->info;
}
}
}
if (isset($name)) {
return isset($info[$name]) ? $info[$name] : [];
}
return $info;
}
/**
* Helper function to scan and collect module .info.yml data.
*
* @return \Drupal\Core\Extension\Extension[]
* An associative array of module information.
*/
function _system_rebuild_module_data() {
$listing = new ExtensionDiscovery(\Drupal::root());
// Find installation profiles. This needs to happen before performing a
// module scan as the module scan requires knowing what the active profile is.
// @todo Remove as part of https://www.drupal.org/node/2186491.
$profiles = $listing->scan('profile');
$profile = drupal_get_profile();
if ($profile && isset($profiles[$profile])) {
// Prime the drupal_get_filename() static cache with the profile info file
// location so we can use drupal_get_path() on the active profile during
// the module scan.
// @todo Remove as part of https://www.drupal.org/node/2186491.
drupal_get_filename('profile', $profile, $profiles[$profile]->getPathname());
}
// Find modules.
$modules = $listing->scan('module');
// Include the installation profile in modules that are loaded.
if ($profile) {
$modules[$profile] = $profiles[$profile];
// Installation profile hooks are always executed last.
$modules[$profile]->weight = 1000;
}
// Set defaults for module info.
$defaults = [
'dependencies' => [],
'description' => '',
'package' => 'Other',
'version' => NULL,
'php' => DRUPAL_MINIMUM_PHP,
];
// Read info files for each module.
foreach ($modules as $key => $module) {
// Look for the info file.
$module->info = \Drupal::service('info_parser')->parse($module->getPathname());
// Add the info file modification time, so it becomes available for
// contributed modules to use for ordering module lists.
$module->info['mtime'] = $module->getMTime();
// Merge in defaults and save.
$modules[$key]->info = $module->info + $defaults;
// Installation profiles are hidden by default, unless explicitly specified
// otherwise in the .info.yml file.
if ($key == $profile && !isset($modules[$key]->info['hidden'])) {
$modules[$key]->info['hidden'] = TRUE;
if (isset($name)) {
return isset($info[$name]) ? $info[$name] : [];
}
// Invoke hook_system_info_alter() to give installed modules a chance to
// modify the data in the .info.yml files if necessary.
// @todo Remove $type argument, obsolete with $module->getType().
$type = 'module';
\Drupal::moduleHandler()->alter('system_info', $modules[$key]->info, $modules[$key], $type);
return $info;
}
// It is possible that a module was marked as required by
// hook_system_info_alter() and modules that it depends on are not required.
foreach ($modules as $module) {
_system_rebuild_module_data_ensure_required($module, $modules);
}
if ($profile && isset($modules[$profile])) {
// The installation profile is required, if it's a valid module.
$modules[$profile]->info['required'] = TRUE;
// Add a default distribution name if the profile did not provide one.
// @see install_profile_info()
// @see drupal_install_profile_distribution_name()
if (!isset($modules[$profile]->info['distribution']['name'])) {
$modules[$profile]->info['distribution']['name'] = 'Drupal';
}
}
return $modules;
}
/**
@@ -1088,8 +1004,14 @@ function _system_rebuild_module_data() {
* The module info.
* @param \Drupal\Core\Extension\Extension[] $modules
* The array of all module info.
*
* @deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. This
* function is no longer used in Drupal core.
*
* @see https://www.drupal.org/node/2709919
*/
function _system_rebuild_module_data_ensure_required($module, &$modules) {
@trigger_error("_system_rebuild_module_data_ensure_required() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. This function is no longer used in Drupal core. See https://www.drupal.org/node/2709919", E_USER_DEPRECATED);
if (!empty($module->info['required'])) {
foreach ($module->info['dependencies'] as $dependency) {
$dependency_name = ModuleHandler::parseDependency($dependency)['name'];
@@ -1103,6 +1025,23 @@ function _system_rebuild_module_data_ensure_required($module, &$modules) {
}
}
/**
* Helper function to scan and collect module .info.yml data.
*
* @return \Drupal\Core\Extension\Extension[]
* An associative array of module information.
*
* @deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0.
* Use \Drupal::service('extension.list.module')->reset()->getList()
* instead. Note: You probably don't need the reset() method.
*
* @see https://www.drupal.org/node/2709919
*/
function _system_rebuild_module_data() {
@trigger_error("_system_rebuild_module_data() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Instead, you should use \\Drupal::service('extension.list.module')->reset()->getList(). See https://www.drupal.org/node/2709919", E_USER_DEPRECATED);
return \Drupal::service('extension.list.module')->reset()->getList();
}
/**
* Rebuild, save, and return data about all currently available modules.
*
@@ -1110,33 +1049,7 @@ function _system_rebuild_module_data_ensure_required($module, &$modules) {
* Array of all available modules and their data.
*/
function system_rebuild_module_data() {
$modules_cache = &drupal_static(__FUNCTION__);
// Only rebuild once per request. $modules and $modules_cache cannot be
// combined into one variable, because the $modules_cache variable is reset by
// reference from system_list_reset() during the rebuild.
if (!isset($modules_cache)) {
$modules = _system_rebuild_module_data();
$files = [];
ksort($modules);
// Add status, weight, and schema version.
$installed_modules = \Drupal::config('core.extension')->get('module') ?: [];
foreach ($modules as $name => $module) {
$module->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0;
$module->status = (int) isset($installed_modules[$name]);
$module->schema_version = SCHEMA_UNINSTALLED;
$files[$name] = $module->getPathname();
}
$modules = \Drupal::moduleHandler()->buildModuleDependencies($modules);
$modules_cache = $modules;
// Store filenames to allow drupal_get_filename() to retrieve them without
// having to rebuild or scan the filesystem.
\Drupal::state()->set('system.module.files', $files);
// Clear the module info cache.
\Drupal::cache()->delete('system.module.info');
drupal_static_reset('system_get_info');
}
return $modules_cache;
return \Drupal::service('extension.list.module')->reset()->getList();
}
/**
@@ -1461,11 +1374,11 @@ function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $repl
$local = $managed ? file_save_data($data, $path, $replace) : file_unmanaged_save_data($data, $path, $replace);
}
catch (RequestException $exception) {
drupal_set_message(t('Failed to fetch file due to error "%error"', ['%error' => $exception->getMessage()]), 'error');
\Drupal::messenger()->addError(t('Failed to fetch file due to error "%error"', ['%error' => $exception->getMessage()]));
return FALSE;
}
if (!$local) {
drupal_set_message(t('@remote could not be saved to @path.', ['@remote' => $url, '@path' => $path]), 'error');
\Drupal::messenger()->addError(t('@remote could not be saved to @path.', ['@remote' => $url, '@path' => $path]));
}
return $local;
+59 -1
View File
@@ -5,7 +5,9 @@
* Post update functions for System.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Entity\Display\EntityDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
@@ -49,7 +51,6 @@ function system_post_update_add_region_to_entity_displays() {
array_map($entity_save, EntityFormDisplay::loadMultiple());
}
/**
* Force caches using hashes to be cleared (Twig, render cache, etc.).
*/
@@ -111,3 +112,60 @@ function system_post_update_change_action_plugins() {
}
}
}
/**
* Change plugin IDs of delete actions.
*/
function system_post_update_change_delete_action_plugins() {
$old_new_action_id_map = [
'comment_delete_action' => 'entity:delete_action:comment',
'node_delete_action' => 'entity:delete_action:node',
];
/** @var \Drupal\system\Entity\Action[] $actions */
$actions = \Drupal::entityTypeManager()->getStorage('action')->loadMultiple();
foreach ($actions as $action) {
if (isset($old_new_action_id_map[$action->getPlugin()->getPluginId()])) {
$action->setPlugin($old_new_action_id_map[$action->getPlugin()->getPluginId()]);
$action->save();
}
}
}
/**
* Force cache clear for language item callback.
*
* @see https://www.drupal.org/node/2851736
*/
function system_post_update_language_item_callback() {
// Empty post-update hook.
}
/**
* Update all entity displays that contain extra fields.
*/
function system_post_update_extra_fields(&$sandbox = NULL) {
$config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
$entity_field_manager = \Drupal::service('entity_field.manager');
$callback = function (EntityDisplayInterface $display) use ($entity_field_manager) {
$display_context = $display instanceof EntityViewDisplayInterface ? 'display' : 'form';
$extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
// If any extra fields are used as a component, resave the display with the
// updated component information.
$needs_save = FALSE;
if (!empty($extra_fields[$display_context])) {
foreach ($extra_fields[$display_context] as $name => $extra_field) {
if ($component = $display->getComponent($name)) {
$display->setComponent($name, $component);
$needs_save = TRUE;
}
}
}
return $needs_save;
};
$config_entity_updater->update($sandbox, 'entity_form_display', $callback);
$config_entity_updater->update($sandbox, 'entity_view_display', $callback);
}
@@ -38,6 +38,11 @@
* @ingroup themeable
*/
#}
{%
set title_classes = [
label_display == 'visually_hidden' ? 'visually-hidden',
]
%}
{% if label_hidden %}
{% if multiple %}
@@ -53,7 +58,7 @@
{% endif %}
{% else %}
<div{{ attributes }}>
<div{{ title_attributes }}>{{ label }}</div>
<div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
{% if multiple %}
<div>
{% endif %}
@@ -15,8 +15,6 @@
* Available variables:
* - message_list: List of messages to be displayed, grouped by type.
* - status_headings: List of all status types.
* - display: (optional) May have a value of 'status' or 'error' when only
* displaying messages of that specific type.
* - attributes: HTML attributes for the element, including:
* - class: HTML classes.
*
@@ -47,7 +47,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.testfor2354889', 'block.block.secondtestfor2354889', 'block.block.thirdtestfor2354889']))
'value' => serialize(array_merge($existing_blocks, ['block.block.testfor2354889', 'block.block.secondtestfor2354889', 'block.block.thirdtestfor2354889'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
@@ -40,7 +40,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.seven_local_actions']))
'value' => serialize(array_merge($existing_blocks, ['block.block.seven_local_actions'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:seven')
@@ -55,7 +55,7 @@ $extensions = $connection->select('config')
$extensions = unserialize($extensions);
$connection->update('config')
->fields([
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]]))
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]])),
])
->condition('name', 'core.extension')
->execute();
@@ -40,7 +40,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.bartik_page_title']))
'value' => serialize(array_merge($existing_blocks, ['block.block.bartik_page_title'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
@@ -55,7 +55,7 @@ $extensions = $connection->select('config')
$extensions = unserialize($extensions);
$connection->update('config')
->fields([
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]]))
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]])),
])
->condition('name', 'core.extension')
->execute();
@@ -40,7 +40,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.seven_secondary_local_tasks']))
'value' => serialize(array_merge($existing_blocks, ['block.block.seven_secondary_local_tasks'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:seven')
@@ -40,7 +40,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.bartik_branding']))
'value' => serialize(array_merge($existing_blocks, ['block.block.bartik_branding'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
@@ -55,7 +55,7 @@ $extensions = $connection->select('config')
$extensions = unserialize($extensions);
$connection->update('config')
->fields([
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]]))
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]])),
])
->condition('name', 'core.extension')
->execute();
@@ -19,7 +19,7 @@ $extensions = $connection->select('config')
$extensions = unserialize($extensions);
$connection->update('config')
->fields([
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_stable' => 0]]))
'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_stable' => 0]])),
])
->condition('name', 'core.extension')
->execute();
@@ -43,7 +43,7 @@ $existing_blocks = unserialize($existing_blocks);
$connection->update('key_value')
->fields([
'value' => serialize(array_merge($existing_blocks, ['block.block.testfor2513534', 'block.block.secondtestfor2513534']))
'value' => serialize(array_merge($existing_blocks, ['block.block.testfor2513534', 'block.block.secondtestfor2513534'])),
])
->condition('collection', 'config.entity.key_store.block')
->condition('name', 'theme:bartik')
@@ -0,0 +1,63 @@
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of https://www.drupal.org/node/2455125.
*/
use Drupal\Component\Uuid\Php;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$view_file = __DIR__ . '/drupal-8.views-taxonomy-parent-2543726.yml';
$view_config = Yaml::decode(file_get_contents($view_file));
$connection->insert('config')
->fields(['collection', 'name', 'data'])
->values([
'collection' => '',
'name' => "views.view.test_taxonomy_parent",
'data' => serialize($view_config),
])
->execute();
$uuid = new Php();
// The root tid.
$tids = [0];
for ($i = 0; $i < 4; $i++) {
$name = $this->randomString();
$tid = $connection->insert('taxonomy_term_data')
->fields(['vid', 'uuid', 'langcode'])
->values(['vid' => 'tags', 'uuid' => $uuid->generate(), 'langcode' => 'en'])
->execute();
$connection->insert('taxonomy_term_field_data')
->fields(['tid', 'vid', 'langcode', 'name', 'weight', 'changed', 'default_langcode'])
->values(['tid' => $tid, 'vid' => 'tags', 'langcode' => 'en', 'name' => $name, 'weight' => 0, 'changed' => REQUEST_TIME, 'default_langcode' => 1])
->execute();
$tids[] = $tid;
}
$hierarchy = [
// Term with tid 1 has terms with tids 2 and 3 as parents.
1 => [2, 3],
2 => [3, 0],
3 => [0],
];
$query = $connection->insert('taxonomy_term_hierarchy')->fields(['tid', 'parent']);
foreach ($hierarchy as $tid => $parents) {
foreach ($parents as $parent) {
$query->values(['tid' => $tids[$tid], 'parent' => $tids[$parent]]);
}
}
$query->execute();

Some files were not shown because too many files have changed in this diff Show More