Commit 534ee0d3 authored by catch's avatar catch
Browse files

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

Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi.shankar, Gábor Hojtsy, heddn, Charlie ChX Negyesi, amateescu: Make Drupal 9 compatible with PHP 7.4
parent 08582f73
......@@ -2292,7 +2292,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'));
......
......@@ -1153,7 +1153,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);
......
......@@ -131,7 +131,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'];
......
......@@ -143,23 +143,22 @@ public function getRequirements() {
/**
* {@inheritdoc}
*/
public function serialize() {
public function __serialize(): array {
// Calling the parent method is safer than trying to optimize out the extra
// function calls.
$data = unserialize(parent::serialize());
$data = parent::__serialize();
$data['fit'] = $this->fit;
$data['patternOutline'] = $this->patternOutline;
$data['numParts'] = $this->numParts;
return serialize($data);
return $data;
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized) {
parent::unserialize($serialized);
$data = unserialize($serialized);
public function __unserialize(array $data): void {
parent::__unserialize($data);
$this->fit = $data['fit'];
$this->patternOutline = $data['patternOutline'];
......
......@@ -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;
}
......
......@@ -751,8 +751,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']
);
}
/**
......
......@@ -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.
......
......@@ -498,7 +498,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'];
......
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\rdf\Traits;
/**
* This is copy of \EasyRdf_ParsedUri from the easyrdf/easyrdf library.
*
* It fixes a PHP 7.4 deprecation in \EasyRdf_ParsedUri::normalise().
*
* @todo https://www.drupal.org/project/drupal/issues/3110972 Remove this work
* around.
*/
/**
* EasyRdf
*
* LICENSE
*
* Copyright (c) 2009-2013 Nicholas J Humfrey. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package EasyRdf
* @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
* @license http://www.opensource.org/licenses/bsd-license.php
*/
/**
* A RFC3986 compliant URI parser
*
* @package EasyRdf
* @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://www.ietf.org/rfc/rfc3986.txt
*/
class EasyRdf_ParsedUri
{
// For all URIs:
private $scheme = null;
private $fragment = null;
// For hierarchical URIs:
private $authority = null;
private $path = null;
private $query = null;
const URI_REGEX = "|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|";
/** Constructor for creating a new parsed URI
*
* The $uri parameter can either be a string or an
* associative array with the following keys:
* scheme, authority, path, query, fragment
*
* @param mixed $uri The URI as a string or an array
* @return object EasyRdf_ParsedUri
*/
public function __construct($uri = null)
{
if (is_string($uri)) {
if (preg_match(self::URI_REGEX, $uri, $matches)) {
if (!empty($matches[1])) {
$this->scheme = isset($matches[2]) ? $matches[2] : '';
}
if (!empty($matches[3])) {
$this->authority = isset($matches[4]) ? $matches[4] : '';
}
$this->path = isset($matches[5]) ? $matches[5] : '';
if (!empty($matches[6])) {
$this->query = isset($matches[7]) ? $matches[7] : '';
}
if (!empty($matches[8])) {
$this->fragment = isset($matches[9]) ? $matches[9] : '';
}
}
} elseif (is_array($uri)) {
$this->scheme = isset($uri['scheme']) ? $uri['scheme'] : null;
$this->authority = isset($uri['authority']) ? $uri['authority'] : null;
$this->path = isset($uri['path']) ? $uri['path'] : null;
$this->query = isset($uri['query']) ? $uri['query'] : null;
$this->fragment = isset($uri['fragment']) ? $uri['fragment'] : null;
}
}
/** Returns true if this is an absolute (complete) URI
* @return boolean
*/
public function isAbsolute()
{
return $this->scheme !== null;
}
/** Returns true if this is an relative (partial) URI
* @return boolean
*/
public function isRelative()
{
return $this->scheme === null;
}
/** Returns the scheme of the URI (e.g. http)
* @return string
*/
public function getScheme()
{
return $this->scheme;
}
/** Sets the scheme of the URI (e.g. http)
* @param string $scheme The new value for the scheme of the URI
*/
public function setScheme($scheme)
{
$this->scheme = $scheme;
}
/** Returns the authority of the URI (e.g. www.example.com:8080)
* @return string
*/
public function getAuthority()
{
return $this->authority;
}
/** Sets the authority of the URI (e.g. www.example.com:8080)
* @param string $authority The new value for the authority component of the URI
*/
public function setAuthority($authority)
{
$this->authority = $authority;
}
/** Returns the path of the URI (e.g. /foo/bar)
* @return string
*/
public function getPath()
{
return $this->path;
}
/** Set the path of the URI (e.g. /foo/bar)
* @param string $path The new value for the path component of the URI
*/
public function setPath($path)
{
$this->path = $path;
}
/** Returns the query string part of the URI (e.g. foo=bar)
* @return string
*/
public function getQuery()
{
return $this->query;
}
/** Set the query string of the URI (e.g. foo=bar)
* @param string $query The new value for the query string component of the URI
*/
public function setQuery($query)
{
$this->query = $query;
}
/** Returns the fragment part of the URI (i.e. after the #)
* @return string
*/
public function getFragment()
{
return $this->fragment;
}
/** Set the fragment of the URI (i.e. after the #)
* @param string $fragment The new value for the fragment component of the URI
*/
public function setFragment($fragment)
{
$this->fragment = $fragment;
}
/**
* Normalises the path of this URI if it has one. Normalising a path means
* that any unnecessary '.' and '..' segments are removed. For example, the
* URI http://example.com/a/b/../c/./d would be normalised to
* http://example.com/a/c/d
*
* @return object EasyRdf_ParsedUri
*/
public function normalise()
{
if (empty($this->path)) {
return $this;
}
// Remove ./ from the start
if (substr($this->path, 0, 2) == './') {
// Remove both characters
$this->path = substr($this->path, 2);
}
// Remove /. from the end
if (substr($this->path, -2) == '/.') {
// Remove only the last dot, not the slash!
$this->path = substr($this->path, 0, -1);
}
if (substr($this->path, -3) == '/..') {
$this->path .= '/';
}
// Split the path into its segments
$segments = explode('/', $this->path);
$newSegments = array();
// Remove all unnecessary '.' and '..' segments
foreach ($segments as $segment) {
if ($segment == '..') {
// Remove the previous part of the path
$count = count($newSegments);
if ($count > 0 && $newSegments[$count-1]) {
array_pop($newSegments);
}
} elseif ($segment == '.') {
// Ignore
continue;
} else {
array_push($newSegments, $segment);
}
}
// Construct the new normalised path
$this->path = implode('/', $newSegments);
// Allow easy chaining of methods
return $this;
}
/**
* Resolves a relative URI using this URI as the base URI.
*/
public function resolve($relUri)
{
// If it is a string, then convert it to a parsed object
if (is_string($relUri)) {
$relUri = new EasyRdf_ParsedUri($relUri);
}
// This code is based on the pseudocode in section 5.2.2 of RFC3986
$target = new EasyRdf_ParsedUri();
if ($relUri->scheme) {
$target->scheme = $relUri->scheme;
$target->authority = $relUri->authority;
$target->path = $relUri->path;
$target->query = $relUri->query;
} else {
if ($relUri->authority) {
$target->authority = $relUri->authority;
$target->path = $relUri->path;
$target->query = $relUri->query;
} else {
if (empty($relUri->path)) {
$target->path = $this->path;
if ($relUri->query) {
$target->query = $relUri->query;
} else {
$target->query = $this->query;
}
} else {
if (substr($relUri->path, 0, 1) == '/') {
$target->path = $relUri->path;
} else {
$path = $this->path;
$lastSlash = strrpos($path, '/');
if ($lastSlash !== false) {
$path = substr($path, 0, $lastSlash + 1);
} else {
$path = '/';