Commit 7330f73d authored by catch's avatar catch

Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi.shankar,...

Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi.shankar, Gábor Hojtsy, heddn, catch, Charlie ChX Negyesi, amateescu: Make Drupal 8 & 9 compatible with PHP 7.4
parent 26189f0a
......@@ -2322,7 +2322,13 @@ function install_config_import_batch() {
// Match up the site UUIDs, the install_base_system install task will have
// installed the system module and created a new UUID.
$system_site = $sync->read('system.site');
\Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'])->save();
// When installing from configuration it is possible that system.site
// configuration is not present. If this occurs a ConfigImporterException will
// by thrown when $config_importer->initialize() is called below and the error
// will be reported to the user.
if ($system_site !== FALSE) {
\Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'])->save();
}
// Create the storage comparer and the config importer.
$storage_comparer = new StorageComparer($sync, \Drupal::service('config.storage'));
......
......@@ -1130,7 +1130,7 @@ function template_preprocess_item_list(&$variables) {
// \Drupal\Core\Render\Element::children(), which cannot be used
// here, since it triggers an error on string values.
foreach ($child as $child_key => $child_value) {
if ($child_key[0] !== '#') {
if (is_int($child_key) || $child_key === '' || $child_key[0] !== '#') {
$child['#items'][$child_key] = $child_value;
unset($child[$child_key]);
}
......
......@@ -966,9 +966,11 @@ private function Identifier()
$className = $this->lexer->token['value'];
while ($this->lexer->lookahead['position'] === ($this->lexer->token['position'] + strlen($this->lexer->token['value']))
&& $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) {
while (
null !== $this->lexer->lookahead &&
$this->lexer->lookahead['position'] === ($this->lexer->token['position'] + strlen($this->lexer->token['value'])) &&
$this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)
) {
$this->match(DocLexer::T_NAMESPACE_SEPARATOR);
$this->matchAny(self::$classIdentifiers);
......
......@@ -117,7 +117,7 @@ public function buildByExtension($extension) {
$library['version'] = \Drupal::VERSION;
}
// Remove 'v' prefix from external library versions.
elseif ($library['version'][0] === 'v') {
elseif (is_string($library['version']) && $library['version'][0] === 'v') {
$library['version'] = substr($library['version'], 1);
}
}
......
......@@ -388,7 +388,9 @@ public function hasChanges() {
public function validateSiteUuid() {
$source = $this->sourceStorage->read('system.site');
$target = $this->targetStorage->read('system.site');
return $source['uuid'] === $target['uuid'];
// It is possible that the storage does not contain system.site
// configuration. In such cases the site UUID cannot be valid.
return $source && $target && $source['uuid'] === $target['uuid'];
}
/**
......
......@@ -243,7 +243,9 @@ public function getFormOptions(array $database) {
];
global $install_state;
$profile = $install_state['parameters']['profile'];
// @todo https://www.drupal.org/project/drupal/issues/3110839 remove PHP 7.4
// work around and add a better message for the migrate UI.
$profile = $install_state['parameters']['profile'] ?? NULL;
$db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
$form['advanced_options']['prefix'] = [
'#type' => 'textfield',
......
......@@ -61,7 +61,9 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) {
$batch['progressive'] = !$form_state->isProgrammed();
$response = batch_process();
if ($batch['progressive']) {
// If the batch has been completed and _batch_finished() called then
// $batch will be NULL.
if ($batch && $batch['progressive']) {
return $response;
}
......
......@@ -78,7 +78,7 @@ public static function children(array &$elements, $sort = FALSE) {
$i = 0;
$sortable = FALSE;
foreach ($elements as $key => $value) {
if ($key === '' || $key[0] !== '#') {
if (is_int($key) || $key === '' || $key[0] !== '#') {
if (is_array($value)) {
if (isset($value['#weight'])) {
$weight = $value['#weight'];
......
......@@ -153,7 +153,7 @@ protected static function checkDestination($destination, array $whitelist) {
protected static function stripDangerousValues($input, array $whitelist, array &$sanitized_keys) {
if (is_array($input)) {
foreach ($input as $key => $value) {
if ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE)) {
if ($key !== '' && ((string) $key)[0] === '#' && !in_array($key, $whitelist, TRUE)) {
unset($input[$key]);
$sanitized_keys[] = $key;
}
......
......@@ -764,8 +764,9 @@ function _color_blend($img, $hex1, $hex2, $alpha) {
* Converts a hex color into an RGB triplet.
*/
function _color_unpack($hex, $normalize = FALSE) {
if (strlen($hex) == 4) {
$hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
$hex = substr($hex, 1);
if (strlen($hex) == 3) {
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
}
$c = hexdec($hex);
for ($i = 16; $i >= 0; $i -= 8) {
......
......@@ -21,7 +21,6 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
$widget_type = $widget_settings['type'];
$field_data = unserialize($field_definition['data']);
$field_settings = $field_data['settings'];
// Get taxonomy term reference handler settings from allowed values.
if ($row->getSourceProperty('type') == 'taxonomy_term_reference') {
......@@ -38,6 +37,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
// Get entityreference handler settings from source field configuration.
if ($row->getSourceProperty('type') == "entityreference") {
$field_settings = $field_data['settings'];
$instance_settings['handler'] = 'default:' . $field_settings['target_type'];
// Transform the sort settings to D8 structure.
$sort = [
......
......@@ -180,9 +180,6 @@ public function prepareRow(Row $row) {
}
}
$field_data = unserialize($row->getSourceProperty('field_data'));
$row->setSourceProperty('field_settings', $field_data['settings']);
return parent::prepareRow($row);
}
......
......@@ -82,7 +82,10 @@ public function normalize($field_item, $format = NULL, array $context = []) {
// Normalize the target entity.
$embedded = $this->serializer->normalize($target_entity, $format, $context);
$link = $embedded['_links']['self'];
// @todo https://www.drupal.org/project/drupal/issues/3110815 $embedded will
// be NULL if the target entity does not exist. Use null coalescence
// operator to preserve behaviour in PHP 7.4.
$link = $embedded['_links']['self'] ?? NULL;
// If the field is translatable, add the langcode to the link relation
// object. This does not indicate the language of the target entity.
if ($langcode) {
......
......@@ -87,6 +87,12 @@ protected function isMultilingual() {
protected function getDefaultLanguageValues() {
$config_storage = BootstrapConfigStorageFactory::get();
$system = $config_storage->read('system.site');
// In Kernel tests it's possible this code is called before system.site
// exists. In such cases behave as though the corresponding language
// configuration entity does not exist.
if ($system === FALSE) {
return FALSE;
}
$default_language = $config_storage->read(static::CONFIG_PREFIX . $system['default_langcode']);
if (is_array($default_language)) {
return $default_language;
......
......@@ -281,13 +281,22 @@ public function providerTestBuild() {
new ReturnPromise([[]]),
'',
];
$data['exception'] = [
new ThrowPromise(new \Exception('The exception message')),
return $data;
}
/**
* @covers ::build
*/
public function testBuildException() {
// In PHP 7.4 ReflectionClass cannot be serialized so this cannot be part of
// providerTestBuild().
$promise = new ThrowPromise(new \Exception('The exception message'));
$this->testBuild(
$promise,
'',
'The field "%field" failed to render with the error of "%error".',
['%field' => 'the_field_name', '%error' => 'The exception message'],
];
return $data;
['%field' => 'the_field_name', '%error' => 'The exception message']
);
}
/**
......
......@@ -185,12 +185,12 @@ public function setValue($values, $notify = TRUE) {
$values += [
'options' => [],
];
}
// Unserialize the values, this is deprecated as the storage takes care of
// this, options must not be passed as a string anymore.
if (is_string($values['options'])) {
@trigger_error('Support for passing options as a serialized string is deprecated in 8.7.0 and will be removed before Drupal 9.0.0. Pass them as an array instead. See https://www.drupal.org/node/2961643.', E_USER_DEPRECATED);
$values['options'] = unserialize($values['options'], ['allowed_classes' => FALSE]);
// Unserialize the values, this is deprecated as the storage takes care of
// this, options must not be passed as a string anymore.
if (is_string($values['options'])) {
@trigger_error('Support for passing options as a serialized string is deprecated in 8.7.0 and will be removed before Drupal 9.0.0. Pass them as an array instead. See https://www.drupal.org/node/2961643.', E_USER_DEPRECATED);
$values['options'] = unserialize($values['options'], ['allowed_classes' => FALSE]);
}
}
parent::setValue($values, $notify);
}
......
......@@ -385,6 +385,11 @@ function locale_translate_batch_finished($success, array $results) {
// file), simply do nothing.
if ($results && isset($results['stats'])) {
foreach ($results['stats'] as $filepath => $report) {
if ($filepath === 'config') {
// Ignore the config entry. It is processed in
// locale_config_batch_finished() below.
continue;
}
$additions += $report['additions'];
$updates += $report['updates'];
$deletes += $report['deletes'];
......
......@@ -78,8 +78,7 @@ public function testConfigRollback() {
$this->assertSame('Some site', $config->get('name'));
$this->assertSame('Awesome slogan', $config->get('slogan'));
// Confirm the map row is deleted.
$map_row = $config_id_map->getRowBySource(['id' => $variable[0]['id']]);
$this->assertNull($map_row['destid1']);
$this->assertFalse($config_id_map->getRowBySource(['id' => $variable[0]['id']]));
// We use system configuration to demonstrate importing and rolling back
// configuration translations.
......
......@@ -648,7 +648,7 @@ function template_preprocess_node(&$variables) {
unset($variables['elements']['uid']);
}
if (!$skip_custom_preprocessing || !$node->getFieldDefinition('title')->isDisplayConfigurable('view')) {
if (isset($variables['elements']['title']) && (!$skip_custom_preprocessing || !$node->getFieldDefinition('title')->isDisplayConfigurable('view'))) {
$variables['label'] = $variables['elements']['title'];
unset($variables['elements']['title']);
}
......
......@@ -495,7 +495,7 @@ function rdf_preprocess_comment(&$variables) {
}
// Adds RDFa markup for the date of the comment.
$created_mapping = $mapping->getPreparedFieldMapping('created');
if (!empty($created_mapping)) {
if (!empty($created_mapping) && isset($comment->rdf_data)) {
// The comment date is precomputed as part of the rdf_data so that it can be
// cached as part of the entity.
$date_attributes = $comment->rdf_data['date'];
......
This diff is collapsed.
......@@ -4,6 +4,14 @@
use Drupal\Core\Url;
/**
* Override \EasyRdf_ParsedUri for PHP 7.4 compatibilty.
*
* @todo https://www.drupal.org/project/drupal/issues/3110972 Remove this work
* around.
*/
class_alias('\Drupal\Tests\rdf\Traits\EasyRdf_ParsedUri', '\EasyRdf_ParsedUri');
/**
* Defines a trait for parsing RDF properties from HTML.
*/
......
......@@ -77,6 +77,9 @@ public function testCalculateDependencies() {
$target_entity_type->expects($this->any())
->method('getBundleEntityType')
->will($this->returnValue(NULL));
$target_entity_type->expects($this->any())
->method('getBundleConfigDependency')
->will($this->returnValue(['type' => 'module', 'name' => 'test_module']));
$this->entityTypeManager->expects($this->at(0))
->method('getDefinition')
......@@ -86,7 +89,10 @@ public function testCalculateDependencies() {
->method('getDefinition')
->with($this->entityTypeId)
->will($this->returnValue($this->entityType));
$this->entityTypeManager->expects($this->at(2))
->method('getDefinition')
->with($this->entityTypeId)
->will($this->returnValue($this->entityType));
$entity = new RdfMapping($values, $this->entityTypeId);
$dependencies = $entity->calculateDependencies()->getDependencies();
$this->assertArrayNotHasKey('config', $dependencies);
......
......@@ -70,7 +70,13 @@ public function prepareRow(Row $row) {
$query->condition('lt.language', $language);
$query->addField('lt', 'translation');
$results = $query->execute()->fetchAssoc();
$row->setSourceProperty($other_property . '_translated', $results['translation']);
if ($results) {
$row->setSourceProperty($other_property . '_translated', $results['translation']);
}
else {
// The translation does not exist.
$row->setSourceProperty($other_property . '_translated', NULL);
}
parent::prepareRow($row);
}
......
......@@ -61,7 +61,7 @@ public function testArgumentValidatorTerm() {
$view->initHandlers();
// Test the single validator for term IDs.
$view->argument['tid']->validator->options['type'] = 'tid';
$view->argument['tid']->options['validate_options']['multiple'] = 0;
// Pass in a single valid term.
foreach ($this->terms as $term) {
......@@ -78,7 +78,7 @@ public function testArgumentValidatorTerm() {
$view->argument['tid']->argument_validated = NULL;
// Test the multiple validator for term IDs.
$view->argument['tid']->validator->options['type'] = 'tids';
$view->argument['tid']->options['validate_options']['multiple'] = 1;
$view->argument['tid']->options['break_phrase'] = TRUE;
// Pass in a single term.
......
......@@ -101,7 +101,7 @@ public function getPath() {
protected function isDefaultTabPath() {
$menu = $this->getOption('menu');
$tab_options = $this->getOption('tab_options');
return $menu['type'] == 'default tab' && !empty($tab_options['type']) && $tab_options['type'] != 'none';
return $menu && $menu['type'] == 'default tab' && !empty($tab_options['type']) && $tab_options['type'] != 'none';
}
/**
......
......@@ -5,6 +5,7 @@
use Drupal\Component\Render\FormattableMarkup;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Plugin\views\filter\NumericFilter;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\views\Plugin\views\filter\InOperator;
......@@ -86,6 +87,9 @@ public function testHandlers() {
if ($handler instanceof InOperator) {
$options['value'] = [1];
}
elseif ($handler instanceof NumericFilter) {
$options['value'] = ['value' => 1];
}
else {
$options['value'] = 1;
}
......
......@@ -137,7 +137,7 @@ public function testLanguageBundleConditions() {
// condition.
$configuration = [
'table' => 'node__field_tags',
'left_table' => 'node',
'left_table' => 'views_test_data',
'left_field' => 'nid',
'field' => 'entity_id',
'extra' => [
......@@ -148,7 +148,7 @@ public function testLanguageBundleConditions() {
],
];
$join_info = $this->buildJoin($view, $configuration, 'node__field_tags');
$this->assertContains('AND (node__field_tags.langcode = .langcode)', $join_info['condition']);
$this->assertContains('AND (node__field_tags.langcode = views_test_data.langcode)', $join_info['condition']);
array_unshift($configuration['extra'], [
'field' => 'deleted',
......@@ -156,7 +156,7 @@ public function testLanguageBundleConditions() {
'numeric' => TRUE,
]);
$join_info = $this->buildJoin($view, $configuration, 'node__field_tags');
$this->assertContains('AND (node__field_tags.langcode = .langcode)', $join_info['condition']);
$this->assertContains('AND (node__field_tags.langcode = views_test_data.langcode)', $join_info['condition']);
// Replace the language condition with a bundle condition.
$configuration['extra'][1] = [
......@@ -173,7 +173,7 @@ public function testLanguageBundleConditions() {
'field' => 'langcode',
];
$join_info = $this->buildJoin($view, $configuration, 'node__field_tags');
$this->assertContains('AND (node__field_tags.bundle = :views_join_condition_1 OR node__field_tags.langcode = .langcode)', $join_info['condition']);
$this->assertContains('AND (node__field_tags.bundle = :views_join_condition_1 OR node__field_tags.langcode = views_test_data.langcode)', $join_info['condition']);
}
/**
......
......@@ -136,6 +136,9 @@ protected function setUp() {
$this->executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
->disableOriginalConstructor()
->getMock();
$this->executable->style_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\style\StylePluginBase')
->disableOriginalConstructor()
->getMock();
$this->display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
->disableOriginalConstructor()
->getMock();
......
......@@ -148,7 +148,7 @@ public function testFieldLoad() {
$this->assertEqual($entity->{$this->fieldName}[$delta]->value, $value);
}
else {
$this->assertFalse(array_key_exists($delta, $entity->{$this->fieldName}));
$this->assertArrayNotHasKey($delta, $entity->{$this->fieldName});
}
}
}
......@@ -160,7 +160,7 @@ public function testFieldLoad() {
$this->assertEqual($entity->{$this->fieldName}[$delta]->value, $value);
}
else {
$this->assertFalse(array_key_exists($delta, $entity->{$this->fieldName}));
$this->assertArrayNotHasKey($delta, $entity->{$this->fieldName});
}
}
......@@ -171,7 +171,7 @@ public function testFieldLoad() {
$connection->insert($this->table)->fields($columns)->values($values)->execute();
$connection->insert($this->revisionTable)->fields($columns)->values($values)->execute();
$entity = $storage->load($entity->id());
$this->assertFalse(array_key_exists($unavailable_langcode, $entity->{$this->fieldName}));
$this->assertArrayNotHasKey($unavailable_langcode, $entity->{$this->fieldName});
}
/**
......
......@@ -610,9 +610,9 @@ protected function tearDown() {
// Remove all prefixed tables.
$original_connection_info = Database::getConnectionInfo('simpletest_original_default');
$original_prefix = $original_connection_info['default']['prefix']['default'];
$original_prefix = $original_connection_info['default']['prefix']['default'] ?? NULL;
$test_connection_info = Database::getConnectionInfo('default');
$test_prefix = $test_connection_info['default']['prefix']['default'];
$test_prefix = $test_connection_info['default']['prefix']['default'] ?? NULL;
if ($original_prefix != $test_prefix) {
$tables = Database::getConnection()->schema()->findTables('%');
foreach ($tables as $table) {
......
......@@ -350,11 +350,15 @@ protected function getResponseLogHandler() {
$html_output = 'Called from ' . $caller['function'] . ' line ' . $caller['line'];
$html_output .= '<hr />' . $request->getMethod() . ' request to: ' . $request->getUri();
// Get the response body as a string. Any errors are silenced as
// tests should not fail if there is a problem. On PHP 7.4
// \Drupal\Tests\migrate\Functional\process\DownloadFunctionalTest
// fails without the usage of a silence operator.
$body = @(string) $response->getBody();
// On redirect responses (status code starting with '3') we need
// to remove the meta tag that would do a browser refresh. We
// don't want to redirect developers away when they look at the
// debug output file in their browser.
$body = $response->getBody();
$status_code = (string) $response->getStatusCode();
if ($status_code[0] === '3') {
$body = preg_replace('#<meta http-equiv="refresh" content=.+/>#', '', $body, 1);
......
......@@ -290,7 +290,7 @@ public function testRenderInvalidType() {
'browsers' => [],
'data' => 'http://example.com/popular.js',
];
$this->renderer->render($css_group);
$this->renderer->render([$css_group]);
}
}
......
......@@ -34,7 +34,11 @@ class: \Drupal\Core\ExampleClass
YAML;
vfsStream::setup('drupal', NULL, [
'modules/example/example.yml' => $yml,
'modules' => [
'example' => [
'example.yml' => $yml,
],
],
]);
$builder = new ContainerBuilder();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment