Problem/Motivation

Drupal 8.8.x is not passing tests on PHP 7.4. PHP 7.4 released on November 28, 2019, a week before Drupal 8.8.0.

Proposed resolution

Fix code to not trigger errors in PHP 7.4 maintaining the same behaviour as PHP 7.0 to 7.3.

There is no release of easyrdf/easyrdf that supports PHP 7.4 in order to work around this we've done #3090017: Isolate test dependency on easyrdf/easyrdf to a single trait and then in this patch we provide a test only version of \EasyRdf_ParsedUri that is PHP 7.4 compatible. This code is only loaded and available at test time. Hopefully a release of easyrdf will happen sometime but it's not as important because it is now a test only dependency in Drupal 9.

Follow-up issues

Done:

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

Drupal [insert version] is now compatible with PHP 7.4 and testing on PHP 7.4 is part of the regular automated test suite.

CommentFileSizeAuthor
#226 3086374-8.8.2-226-do-not-test.patch39.8 KBnils.destoop
#218 3086374-8.8.x-218.patch41.77 KBalexpott
#213 209-213-interdiff.txt2.58 KBalexpott
#213 3086374-8.9.x-213.patch43.69 KBalexpott
#209 3086374-9.0.x-209.patch43.3 KBalexpott
#209 205-209-interdiff.txt912 bytesalexpott
#205 3086374-9.0.x-205.patch43.25 KBalexpott
#205 201-205-interdiff.txt2.11 KBalexpott
#201 3086374-9.0.x-201.patch42.73 KBalexpott
#201 200-201-interdiff.txt582 bytesalexpott
#200 3086374-9.0.x-198.patch43.07 KBalexpott
#200 196-198-interdiff.txt1.78 KBalexpott
#196 3086374-9.0.x-196.patch42.88 KBalexpott
#196 193-196-interdiff.txt1.01 KBalexpott
#193 3086374-9.0.x-193.patch42.99 KBalexpott
#193 192-193-interdiff.txt929 bytesalexpott
#192 3086374-9.0.x-192.patch42.09 KBalexpott
#192 186-192-interdiff.txt1.55 KBalexpott
#186 3086374-9.0.x-186.patch42.85 KBalexpott
#186 185-186-interdiff.txt1.15 KBalexpott
#185 3086374-9.0.x-185.patch41.7 KBalexpott
#185 184-185-interdiff.txt1.52 KBalexpott
#184 3086374-9.0.x-184.patch40.18 KBalexpott
#184 182-184-interdiff.txt4.8 KBalexpott
#182 3086374-9.0.x-182.patch35.38 KBalexpott
#182 180-182-interdiff.txt595 bytesalexpott
#180 3086374-9.0.x-180.patch34.8 KBalexpott
#180 178-180-interdiff.txt2.51 KBalexpott
#178 3086374-9.0.x-178.patch34.57 KBalexpott
#178 177-178-interdiff.txt6.87 KBalexpott
#177 3086374-9.0.x-177.patch41.44 KBalexpott
#177 176-177-interdiff.txt2.18 KBalexpott
#176 3086374-9.0.x-176.patch41.51 KBalexpott
#175 3086374-175.patch33.25 KBmondrake
#168 3086374-167.patch34.48 KBmondrake
#168 interdiff_163-167.txt1.91 KBmondrake
#163 3086374-163.patch32.7 KBSpokje
#161 3086374-161.patch34.39 KBravi.shankar
#155 3086374-155.patch35.9 KBmondrake
#155 interdiff_153-155.txt640 bytesmondrake
#153 interdiff_151-153.txt12.71 KBmondrake
#153 3086374-153.patch35.45 KBmondrake
#151 3086374-151.patch45.76 KBmondrake
#146 3086374-146.patch46.52 KBmondrake
#142 interdiff_139-142.txt1.03 KBmondrake
#142 3086374-142.patch47.34 KBmondrake
#139 interdiff_138-139.txt668 bytesmondrake
#139 3086374-139.patch48.38 KBmondrake
#138 interdiff_136-138.txt1.42 KBmondrake
#138 3086374-138.patch49.04 KBmondrake
#136 interdiff_128-136.txt975 bytesmondrake
#136 3086374-136.patch49 KBmondrake
#128 interdiff_125-128.txt918 bytesmondrake
#128 3086374-128.patch49.13 KBmondrake
#125 3086374-125.patch49.04 KBmondrake
#125 interdiff_118-125.txt3.25 KBmondrake
#118 interdiff_109-118.txt831 bytesmondrake
#118 3086374-118.patch49.81 KBmondrake
#109 3086374-109.patch49.88 KBmondrake
#109 interdiff_108-109.txt1.2 KBmondrake
#108 3086374-108.patch49.59 KBmondrake
#108 interdiff_104-108.txt2.53 KBmondrake
#104 interdiff_103-104.txt4.75 KBmondrake
#104 3086374-104.patch49.44 KBmondrake
#103 interdiff_89-103.txt8.39 KBmondrake
#103 3086374-103.patch47.47 KBmondrake
#89 3086374-3-89.patch49.69 KBalexpott
#89 87-89-interdiff.txt679 bytesalexpott
#87 3086374-3-87.patch49.7 KBalexpott
#87 84-87-interdiff.txt617 bytesalexpott
#84 3086374-3-84.patch49.63 KBalexpott
#83 3086374-3-81.patch51.67 KBalexpott
#81 3086374-3-81.patch54.04 KBalexpott
#81 79-81-interdiff.txt488 bytesalexpott
#79 3086374-3-79.patch51.61 KBalexpott
#79 77-79-interdiff.txt12.56 KBalexpott
#77 3086374-3-77.patch38.87 KBalexpott
#77 75-77-interdiff.txt3.52 KBalexpott
#75 interdiff_74-75.txt1.14 KBmondrake
#75 3086374-75.patch38.02 KBmondrake
#74 interdiff_70-74.txt905 bytesmondrake
#74 3086374-74.patch37.44 KBmondrake
#73 interdiff_70-73.txt1.55 KBmondrake
#73 3086374-73.patch37.41 KBmondrake
#70 3086374-70.patch36.56 KBmondrake
#70 interdiff_69-70.txt717 bytesmondrake
#69 3086374-69.patch36.7 KBmondrake
#69 interdiff_64-69.txt1.28 KBmondrake
#65 interdiff_64_to_65.txt3.68 KBjoseph.olstad
#65 3086374-65.patch40.37 KBjoseph.olstad
#64 interdiff_62-64.txt651 bytesmondrake
#64 3086374-64.patch36.78 KBmondrake
#62 3086374-62.patch36.06 KBmondrake
#62 interdiff_61-62.txt2.8 KBmondrake
#61 3086374-2-60.patch35.33 KBalexpott
#61 55-60-interdiff.txt1.48 KBalexpott
#55 3086374-2-55.patch35.78 KBalexpott
#55 54-55-interdiff.txt1.89 KBalexpott
#54 interdiff_51-54.txt2 KBmondrake
#54 3086374-54.patch34.74 KBmondrake
#51 3086374-51.patch34.76 KBmondrake
#51 interdiff_47-51.txt2.57 KBmondrake
#47 3086374-2-47.patch32.27 KBalexpott
#47 46-47-interdiff.txt904 bytesalexpott
#46 3086374-2-46.patch33.15 KBalexpott
#46 44-46-interdiff.txt685 bytesalexpott
#44 3086374-44.patch32.48 KBmondrake
#44 interdiff_40.44.txt2.16 KBmondrake
#40 interdiff_39-40.txt1.88 KBmondrake
#40 3086374-40.patch30.32 KBmondrake
#39 3086374-2-39.patch32.2 KBalexpott
#39 37-39-interdiff.txt2.67 KBalexpott
#37 interdiff_36-37.txt985 bytesmondrake
#37 3086374-37.patch31.09 KBmondrake
#36 3086374-36.patch31.08 KBmondrake
#36 interdiff_35-36.txt727 bytesmondrake
#35 3086374-35.patch31.06 KBmondrake
#35 interdiff_31-35.txt1.12 KBmondrake
#31 30-31-interdiff.txt1.24 KBalexpott
#31 3086374-2-31.patch30.74 KBalexpott
#30 3086374-2-30.patch30.25 KBalexpott
#30 29-30-interdiff.txt6.46 KBalexpott
#29 3086374-2-29.patch30.32 KBalexpott
#29 23-29-interdiff.txt7.42 KBalexpott
#23 interdiff_18-23.txt1.61 KBmondrake
#23 3086374-23.patch29.36 KBmondrake
#18 3086374-18.patch29.34 KBmondrake
#18 interdiff_13-18.txt10.18 KBmondrake
#13 3086374-13-DISCOVERY.patch22.31 KBmondrake
#13 interdiff_12-13.txt3.42 KBmondrake
#12 interdiff_11-12.txt5.42 KBmondrake
#12 3086374-12-DISCOVERY.patch22.96 KBmondrake
#11 interdiff_10-11.txt1.37 KBmondrake
#11 3086374-11-DISCOVERY.patch18.21 KBmondrake
#10 3086374-10-DISCOVERY.patch16.97 KBmondrake
#10 interdiff_9-10.txt4.41 KBmondrake
#9 3086374-9-DISCOVERY.patch12.56 KBmondrake
#9 interdiff_7-9.txt5.95 KBmondrake
#7 3086374-7-DISCOVERY.patch10.86 KBmondrake
#5 3086374-5-DISCOVERY.patch7.55 KBmondrake
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

mondrake’s picture

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

mondrake’s picture

Issue summary: View changes

c/p from IS of #3085735: Support PHP 7.4 in Drupal 8 to close that as duplicate.

mondrake’s picture

A patch to test how many failures we get after upgrading some dependencies and quickfixing some of the other code as per the IS.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

alexpott’s picture

  1. +++ b/core/lib/Drupal/Component/Annotation/Doctrine/DocParser.php
    @@ -966,13 +966,16 @@ private function Identifier()
    +        $position = isset($this->lexer->lookahead) ? $this->lexer->lookahead['position'] : null;
    ...
    +            $position = isset($this->lexer->lookahead) ? $this->lexer->lookahead['position'] : null;
    

    Let's use the null coalescence operator... see https://3v4l.org/731YX.

  2. +++ b/core/modules/field/src/Plugin/migrate/process/d7/FieldInstanceSettings.php
    @@ -21,7 +21,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
    -    $field_settings = $field_data['settings'];
    +    $field_settings = !empty($field_data) ? $field_data['settings'] : NULL;
    

    Let's use the null coalescence operator... see https://3v4l.org/731YX.

  3. +++ b/core/modules/language/src/LanguageServiceProvider.php
    @@ -87,7 +87,8 @@ protected function isMultilingual() {
    +    $system_default_langcode = !empty($system) ? $system['default_langcode'] : '';
    +    $default_language = $config_storage->read(static::CONFIG_PREFIX . $system_default_langcode);
    

    Let's use the null coalescence operator... see https://3v4l.org/731YX.

  4. +++ b/core/modules/rdf/src/Entity/RdfMapping.php
    @@ -148,7 +148,12 @@ public function calculateDependencies() {
    +    else {
    +      $this->addDependency(NULL, NULL);
    +    }
    

    This is unnecessary.

mondrake’s picture

Done #8, thanks.

No longer necessary to upgrade other packages than phar-stream-wrapper, apparently.

Added some more tweaks.

mondrake’s picture

mondrake’s picture

Too many fails, let's restrict test runs to Unit and Kernel tests and focus on that.

mondrake’s picture

mondrake’s picture

alexpott’s picture

+++ b/core/lib/Drupal/Core/Render/Element.php
@@ -78,7 +78,8 @@ public static function children(array &$elements, $sort = FALSE) {
-      if ($key === '' || (is_string($key) && $key[0] !== '#')) {
+      $key = (string) $key;
+      if ($key === '' || $key[0] !== '#') {

+++ b/core/lib/Drupal/Core/Security/RequestSanitizer.php
@@ -153,6 +153,7 @@ protected static function checkDestination($destination, array $whitelist) {
+        $key = (string) $key;

I don't think we should be string casting the key here... why didn't you copy the if ($key === '' || (is_string($key) && $key[0] !== '#')) { to the RequestSanitizer?

mondrake’s picture

#13 is down to 107 fails in total!

#14 because otherwise the entire element render is an empty string, hence the thousand of failures. If the $key is numeric we still need to render the element. Or am I missing somethig?

alexpott’s picture

Maybe it'd be clearer as

if ($key === '' || is_integer($key) || $key[0] !== '#') {

I think that'd work without the cast.

Also PHP7.4 compatible release of typo3/phar-stream-wrapper is available... 3.1.3 yay!

mondrake’s picture

Assigned: Unassigned » mondrake
Category: Plan » Task

On it.

Changing from plan to task, too - this seems closer now.

mondrake’s picture

Done #16, added more tweaks.

mondrake’s picture

alexpott’s picture

+++ b/core/includes/install.core.inc
@@ -2323,7 +2323,7 @@ function install_config_import_batch() {
-  \Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'])->save();
+  \Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'] ?? NULL)->save();

I think I must be missing something but I'm not sure why this type of change is needed. If the uuid key was not set we'd get an error in PHP7.3 too (as far as I know).

mondrake’s picture

Assigned: mondrake » Unassigned

#20 did that because of

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\FunctionalTests\Installer\InstallerExistingConfigNoConfigTest
E                                                                   1 / 1 (100%)

Time: 5.02 seconds, Memory: 4.00 MB

There was 1 error:

1) Drupal\FunctionalTests\Installer\InstallerExistingConfigNoConfigTest::testConfigSync
Exception: Notice: Trying to access array offset on value of type bool
install_config_import_batch()() (Line: 2326)

alexpott’s picture

Interesting - so we need to code for when $system_site is FALSE here. I don't think we should be writing it here (when it is FALSE)

mondrake’s picture

Ghost of Drupal Past’s picture

  1. +++ b/core/includes/theme.inc
    @@ -1128,7 +1128,7 @@ function template_preprocess_item_list(&$variables) {
    +              if (is_integer($child_key) || $child_key[0] !== '#') {
    

    You wanted ctype_digit

  2. +++ b/core/lib/Drupal/Component/Annotation/Doctrine/DocParser.php
    @@ -987,7 +990,7 @@ private function Value()
    +        if (!empty($peek) && DocLexer::T_EQUALS === $peek['type']) {
    

    if ($peek &&) We know it's defined, no need for the !empty wrapper.

  3. +++ b/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
    @@ -49,6 +49,9 @@ public function render(array $css_assets) {
    +      if (empty($css_asset)) {
    

    Same. if (!$css_asset).

  4. +++ b/core/lib/Drupal/Core/Form/FormSubmitter.php
    @@ -61,7 +61,7 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) {
    +      if ($batch['progressive'] ?? NULL) {
    

    Since I am nitpicking anyways why don't we ?? FALSE. You are type coercing to boolean right after anyways.

  5. +++ b/core/lib/Drupal/Core/Security/RequestSanitizer.php
    @@ -153,7 +153,7 @@ protected static function checkDestination($destination, array $whitelist) {
    +        if (is_integer($key) || ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE))) {
    

    ctype_digit

  6. +++ b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
    @@ -188,7 +188,7 @@ public function setValue($values, $notify = TRUE) {
    +    if (isset($values['options']) && is_string($values['options'])) {
    

    After using ?? so much, why is it not used here? is_string($values['options'] ?? NULL)

  7. +++ b/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
    @@ -152,7 +152,7 @@ public function testLocaleTranslationJsDependencies() {
    +    $js_filename = $prefix . '_' . ($js_translation_files[$prefix] ?? NULL) . '.js';
    

    ?? ''

  8. +++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
    @@ -101,7 +101,7 @@ public function getPath() {
    +    return !empty($menu) && $menu['type'] == 'default tab' && !empty($tab_options['type']) && $tab_options['type'] != 'none';
    

    No need for !empty again. Just $menu && is enough. And since we are touching this ancient code could we please change the == to === and the != to !== please while at it?

  9. +++ b/core/modules/views/src/Plugin/views/filter/StringFilter.php
    @@ -341,7 +341,7 @@ protected function opContainsWord($field) {
    +      if ($match[2][0] == '"') {
    

    Yeah triple equals here would be nice too.

  10. +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityViewBuilderTest.php
    @@ -194,7 +194,7 @@ public function testEntityViewBuilderWeight() {
    +    $this->assertEqual($view['label']['#weight'] ?? NULL, 20, 'The weight of a display component is respected.');
    

    Same ?? ''

  11. +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityTranslationTest.php
    @@ -664,7 +664,7 @@ protected function doTestLanguageFallback($entity_type) {
    +    $this->assertEqual($build['label']['#markup'] ?? NULL, $values[$current_langcode]['name'], 'By default the entity is rendered in the current language.');
    

    ?? ''. assertEquals IMO is a wrapper around the dreaded== and NULL == 0 among other things. No need for that.

  12. +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityViewBuilderTest.php
    @@ -194,7 +194,7 @@ public function testEntityViewBuilderWeight() {
    +    $this->assertEqual($view['label']['#weight'] ?? NULL, 20, 'The weight of a display component is respected.');
    

    Same ?? ''.

mondrake’s picture

AFK from now. If anyone wants to take this on feel free :)

The last submitted patch, 18: 3086374-18.patch, failed testing. View results

alexpott’s picture

Issue summary: View changes
alexpott’s picture

Another dependency needs an update - https://github.com/njh/easyrdf/pull/311

alexpott’s picture

Thanks for the review @Charlie ChX Negyesi
1. I think is_int() here is fine - we are only concerned with integer array keys - string ones can be checked as per usual.
2. $peek can be NULL - changed to be more explicit
3. Hopefully this code can be removed it looks unnecessary.
4. Hopefully this code can be removed it looks unnecessary as well.
5. See 1.
6. Refactored as we can move the block inside the previous if.
7. Fixed
8. Fixed but didn't make the other changes. I think we should limit the changes here. Nothing unnecessary should be done.
9. I think we should do this later
10. Hopefully this change is unnecessary. Removed it.
11. Same as 10.
12. This is the same as 10.

alexpott’s picture

  1. +++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
    @@ -82,7 +82,7 @@ public function normalize($field_item, $format = NULL, array $context = []) {
    -    $link = $embedded['_links']['self'];
    +    $link = $embedded['_links']['self'] ?? NULL;
    

    This needs more explanation - we're using link as an array later.

  2. +++ b/core/modules/rdf/rdf.module
    @@ -498,7 +498,7 @@ function rdf_preprocess_comment(&$variables) {
       if (!empty($created_mapping)) {
         // 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'];
    +    $date_attributes = $comment->rdf_data['date'] ?? NULL;
     
         $rdf_metadata = [
    

    This needs more thought. It doesn't look right.

  3. +++ b/core/modules/node/node.module
    @@ -649,7 +649,7 @@ function template_preprocess_node(&$variables) {
       if (!$skip_custom_preprocessing || !$node->getFieldDefinition('title')->isDisplayConfigurable('view')) {
    -    $variables['label'] = $variables['elements']['title'];
    +    $variables['label'] = $variables['elements']['title'] ?? NULL;
         unset($variables['elements']['title']);
       }
    

    This one looks a bit odd. Why was this needed?

alexpott’s picture

So mikey179/vfsstream 2.0.x-dev fixes some of our tests. So either we need to work out what fixes this and get it backported to the 1.x branch or get a release of 2.0... fun.

Status: Needs review » Needs work

The last submitted patch, 31: 3086374-2-31.patch, failed testing. View results

mondrake’s picture

Looks like also Composer yet needs to release a PHP 7.4 compatibile version including https://github.com/composer/composer/pull/8296

In the meantime dev-master could do, apparently.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

xjm’s picture

Priority: Major » Critical
alexpott’s picture

One more fix due to

Fatal error: Uncaught Exception: Serialization of 'ReflectionClass' is not allowed in /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/Framework/TestCase.php:842
Stack trace:
#0 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/Framework/TestCase.php(842): serialize(Array)
#1 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/Framework/TestSuite.php(755): PHPUnit\Framework\TestCase->run(Object(PHPUnit\Framework\TestResult))
#2 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/Framework/TestSuite.php(755): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#3 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(545): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#4 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/TextUI/Command.php(195): PHPUnit\TextUI\TestRunner->doRun(Object(PHPUnit\Framework\TestSuite), Array, true)
#5 /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/php in /Users/alex/dev/sites/drupal8alt.dev/vendor/phpunit/phpunit/src/Framework/TestCase.php on line 842
mondrake’s picture

mondrake’s picture

Issue summary: View changes

Just a note that mikey179/vfsstream 2.0.x-dev requires PHP 7.2 , so D8.8. cannot upgrade to it - a 1.x version upstream would be needed?

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Status: Needs review » Needs work

The last submitted patch, 44: 3086374-44.patch, failed testing. View results

alexpott’s picture

We can fix the ArchiveTar issue by letting ArchiveTar determine if the file is compressed rather than passing the compression type in.

alexpott’s picture

The change in core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php is breaking \Drupal\Tests\hal\Kernel\EntityTranslationNormalizeTest so reverting and seeing which test that is "fixing" because maybe the test is wrong.

The last submitted patch, 46: 3086374-2-46.patch, failed testing. View results

alexpott’s picture

HMmm I was wrong in #46 - that's not enough to make the ArchiveTar issues go away. We're going to need a fix upstream.

mondrake’s picture

Assigned: Unassigned » mondrake

Working on the views test failures.

alexpott’s picture

@mondrake I know using the null coalescence operator is tempting and these fixes kinda preserve the PHP 7.3 (and below) behaviour

+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -263,7 +263,8 @@ public function buildJoin($select_query, $table, $view_query) {
-      $left_field = "$left_table[alias].$this->leftField";
+      $left_table_alias = $left_table['alias'] ?? $left_table;
+      $left_field = "$left_table_alias.$this->leftField";

But I'm concerned that this is our code talking to us and saying that what we think is true here actually is not - yes PHP used to continue on blindly up the garden path but we're not doing that anymore because your code does not make sense.

Like this specific thing looks like a bugfix - so do we need additional tests - is the fix correct etc...

alexpott’s picture

+++ b/core/lib/Drupal/Core/Controller/ArgumentResolver/RawParameterValueResolver.php
@@ -15,7 +15,7 @@
-    return !$argument->isVariadic() && $request->attributes->has('_raw_variables') && array_key_exists($argument->getName(), $request->attributes->get('_raw_variables'));
+    return !$argument->isVariadic() && $request->attributes->has('_raw_variables') && array_key_exists($argument->getName(), (array) $request->attributes->get('_raw_variables'));

Where is _raw_variables set and not an array - that seems like a bug.

mondrake’s picture

@alexpott you're right, obvioulsy... let's do this one more, then have a general look and start spinning off specific issues? My concern is that tests will fail if we do not use combined patches, though.

alexpott’s picture

So re #53 we have other places that assume _raw_variables is a ParameterBag (for example \Drupal\Core\Path\PathValidator::getUrl) - so I think we can here too. What's super interesting is that I'm pretty sure that the RawParameterValueResolver is not working at all!

yield $request->attributes->get('_raw_variables')[$argument->getName()];

Will fail with PHP Error: Cannot use object of type Symfony/Component/DependencyInjection/ParameterBag/ParameterBag as array

But we never get here because in HEAD

return !$argument->isVariadic() && $request->attributes->has('_raw_variables') && array_key_exists($argument->getName(), $request->attributes->get('_raw_variables'));

never returns TRUE because array_key_exists($argument->getName(), $request->attributes->get('_raw_variables') is nonsense.

Not fixing \Drupal\Core\Controller\ArgumentResolver\RawParameterValueResolver::resolve here because I want to see what breaks. I guess nothing. We should file a child issue to fix this.

Also added an @todo to resolve core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php properly. I think this is a good thing for breaking out into a child issue too.

alexpott’s picture

@mondrake see #55 interdiff... it's really helpful if you can add @todo's to the fail tests that the null coalescence operator is fixing - that we we can remove the "fix" and play around with other solutions quicker.

alexpott’s picture

alexpott’s picture

Status: Needs review » Needs work

The last submitted patch, 55: 3086374-2-55.patch, failed testing. View results

mondrake’s picture

Issue summary: View changes
alexpott’s picture

We have a pear release! I removed the core/composer.json updates because they're not necessary in this issue and just add noise.

+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -82,7 +82,10 @@ public function normalize($field_item, $format = NULL, array $context = []) {
-    $link = $embedded['_links']['self'];
+    // @todo $embedded can be NULL - this breaks PHP 7.4 testing. Using the null
+    //   coalescence operator fixes
+    //   Drupal\Tests\node\Functional\Hal\NodeHalJsonAnonTest for example.
+    $link = $embedded['_links']['self'] ?? [];

I discussed this a bit with @Wim Leers who pointed out

There’s these kinds of problems with halall over to be honest.
hence #3049856: [policy] Mark HAL module as deprecated in D9 so it can be removed in D10

I think the best thing here would be to add the @todo and avert our eyes. We have the same behaviour as in PHP7.3 this problem will go away when HAL is removed and at least we've added a @todo if someone takes this up in contrib.

mondrake’s picture

Added @todos as per #56.

I was trying to look into the annotation parsing test failures, very obscure to me... it looks like something is wrong with the deprecation error handlers, but cannot figure out what.

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Component\Annotation\Doctrine\DocParserTest
EEEEEE.....................EE...E.E.E....E.....................  63 / 227 ( 27%)
........E.................E....................EE...E.E.E....E. 126 / 227 ( 55%)
............................E.................E................ 189 / 227 ( 83%)
.........EE..EEEEE.EEE..EEEESE.EEEEEEE                          227 / 227 (100%)

Time: 359 ms, Memory: 6.00 MB

There were 44 errors:

1) Drupal\Tests\Component\Annotation\Doctrine\DocParserTest::testNestedArraysWithNestedAnnotation
Trying to access array offset on value of type null

/var/www/html/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php:165
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:995
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:687
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:663
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:354
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:518
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:744
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:663
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:354
/var/www/html/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php:35

[...]
PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Component\Annotation\Doctrine\Ticket\DCOM58Test
EEEEEE                                                              6 / 6 (100%)

Time: 2.06 seconds, Memory: 4.00 MB

There were 6 errors:

1) Drupal\Tests\Component\Annotation\Doctrine\Ticket\DCOM58Test::testIssue
Trying to access array offset on value of type null

/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:995
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:687
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:663
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php:354
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php:401
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php:334
/var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php:214
/var/www/html/core/tests/Drupal/Tests/Component/Annotation/Doctrine/Ticket/DCOM58Test.php:34

[...]
joseph.olstad’s picture

Would be great to see green soon, @Taran2L single handedly did the D7 compatibility and all tests are passing for D7. There might be some synergies with his work and the work that needs to happen in the D8 branch.

For this reason I've linked the D7 php 7.4.x compatibility issue here as related.

joseph.olstad’s picture

joseph.olstad’s picture

I looked at the various fails and the test code, nothing obvious at the moment. Would have to put a backtrace right before the failure and dump it to file.
My advice, crank up your memory_limit to 1024M in your php.ini
Then put in a backtrace like this somewhere right in the failed line of code core/lib/Drupal/Core/StreamWrapper/LocalStream.php on line 211

if ($fp = fopen('backtrace.log', 'w'))
{
   $bt = debug_backtrace();
   fwrite($fp, 'debug='.print_r($bt, true));
   fclose($fp);
}

the backtrace.log file should go into the root of the D8 folder.

***BEGIN NEW NOTE***
Ah, I see from the issue description, looks like a bit of followup needed upstream still, explains most of the issues. Looks like the plan is almost complete.
***END NEW NOTE***

Keep up the great work! Almost there.

mondrake’s picture

mondrake’s picture

@joseph.olstad thanks - re #65 please note a separate issue to upgrade phar-stream-wrapper exists already and is RTBC, #3088853: Require typo3/phar-stream-wrapper ^3.1.3 and pear/archive_tar ^1.4.8 in order to support PHP 7.4.

mondrake’s picture

alexpott’s picture

@mondrake unfortunately whatever has been backported to the 1.x branch on vfsstream is not enough :( I was going to bisect and see which commits we need backported. Just haven't got round to it yet.

mondrake’s picture

@alexpott yep :(

Also, it looks like Composer master is still not full PHP 7.4 compliant, see the failing test

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Composer\Plugin\Scaffold\Functional\ComposerHookTest
E                                                                   1 / 1 (100%)

Time: 663 ms, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\Composer\Plugin\Scaffold\Functional\ComposerHookTest::testComposerHooks
RuntimeException: Exit code: 1

Loading composer repositories with package information

                                                       
  [ErrorException]                                     
  Trying to access array offset on value of type null  
                                                       

install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] []...





/var/www/html/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/ExecTrait.php:31
/var/www/html/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ComposerHookTest.php:89

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

There's a waiting PR https://github.com/composer/composer/pull/8386, but I don't know if this is going to fix it

mondrake’s picture

Adding a fix for ArgumentValidatorTermTest. However I think this is not correct - the validator property should be initialised beforehand. Added a @todo for a better solution.

The views related failures (see the @todos) require someone knowing the ins and outs of the module...

mondrake’s picture

mondrake’s picture

Upping doctrine/annotations to at least 1.7 seems to solve the annotation test failures. If this is OK then we should spin off an issue to update it in D8.8.x

mondrake’s picture

Unfortunately, doctrine/annotation 1.7.0 requires PHP ^7.1 :(

alexpott’s picture

So the doctrine issues shows that our copied tests from #2631202: Doctrine no longer supports SimpleAnnotationReader, incorporate a solution into core weren't copied correctly and we're not testing what we think we are. Going to split this out into a separate critical issue.

Removed composer.json changes as they're not necessary (at this point) are will only end up with the patch being in needs reroll all the time. Also moved back to vfsstream dev-master because it has fixes we need. So we need to file an upstream issue for that.

alexpott’s picture

alexpott’s picture

Patch adds a work around for https://github.com/njh/easyrdf/pull/311 - I'm concerned that EasyRDF is not very actively maintained.

Also fixes \Drupal\Tests\migrate\Functional\process\DownloadFunctionalTest

Status: Needs review » Needs work

The last submitted patch, 79: 3086374-3-79.patch, failed testing. View results

alexpott’s picture

More EasyRDF fix... also need to open an issue to move that to dev dependencies as that's what it is.

alexpott’s picture

That EasyRDF exists already - #2901363: Move easyrdf/easyrdf to require-dev

alexpott’s picture

alexpott’s picture

joseph.olstad’s picture

@alexpott, nice work, only 2 fails! I believe you forgot to create an interdiff, however no worries, just easier to follow with an interdiff but not necessary, it is getting closer!

joseph.olstad’s picture

something weird with the test results, I don'T see the failures, the console log is all green but there is 2 fails flagged on the results page.

alexpott’s picture

@joseph.olstad #84 was a reroll because #3089530: Tests of copied Doctrine code are not testing what we want them to test caused a conflict - it's tricky to interdiff a reroll.

Here's a fix for the remaining fails I think. We need to update the composer binary to the snapshot channel since 1.9.0 is not PHP7.4 compatible.

mondrake’s picture

#86 yes I noticed that too - looks like the testing infrastructure is not reporting all the fails. If you click on 'View results on dispatcher' link in the rsults page, though, the test failures are there.

#87 aha so in this case the failure is not related to composer as 'the library installed in vendor', but to composer as 'the instance used by the testbot to build the codebase'

alexpott’s picture

@mixologic thinks that \Drupal\Core\Composer\Composer::ensureComposerVersion() is going to fail when we do the composer update properly... it's not failing locally for me... so lets see.

alexpott’s picture

  1. +++ b/core/includes/theme.inc
    @@ -819,7 +819,7 @@ function template_preprocess_image(&$variables) {
    -      if (array_key_exists($key, $variables['attributes'])) {
    +      if (array_key_exists($key, (array) $variables['attributes'])) {
    

    @mondrake do you remember why this is needed? Looking at drupal_common_theme() $variables['attributes'] should default to an array.

  2. +++ b/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
    @@ -49,6 +49,9 @@ public function render(array $css_assets) {
    +      if (empty($css_asset)) {
    +        throw new \Exception('Invalid CSS asset type.');
    +      }
    

    If this is necessary we should split this out into a separate issue and test. @mondrake do you remember which test you added this for.

  3. +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
    @@ -117,7 +117,7 @@ public function buildByExtension($extension) {
    -        elseif ($library['version'][0] === 'v') {
    +        elseif (((string) $library['version'])[0] === 'v') {
    

    Pondering if this is the right fix. I think maybe elseif (is_string($library['version']) && $library['version'][0] === 'v') { might be better. Or maybe the better fix is to ensure that version is always a string by doing $library['version'] = (string) $library['version'] somewhere. Not sure.

  4. +++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
    @@ -243,7 +243,7 @@ public function getFormOptions(array $database) {
    -    $profile = $install_state['parameters']['profile'];
    +    $profile = $install_state['parameters']['profile'] ?? NULL;
    

    What test caused this. It shouldn't be possible to get to the database form without have a profile selected.

  5. +++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
    @@ -168,7 +168,7 @@ public function getPreconfiguredOptions($field_type) {
    -    return $plugin_definition['class'];
    +    return $plugin_definition['class'] ?? NULL;
    

    This definitely looks interesting. @mondrake any idea which test caused us to need this.

  6. +++ b/core/lib/Drupal/Core/Field/WidgetBase.php
    @@ -456,8 +456,8 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
    -            $original_delta = $field_state['original_deltas'][$delta];
    -            $delta_element = $element[$original_delta];
    +            $original_delta = $field_state['original_deltas'][$delta] ?? NULL;
    +            $delta_element = $element[$original_delta] ?? NULL;
    

    It'd be great to know which test caused this to change.

  7. +++ b/core/lib/Drupal/Core/Form/FormSubmitter.php
    @@ -61,7 +61,7 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) {
           $batch['progressive'] = !$form_state->isProgrammed();
           $response = batch_process();
    -      if ($batch['progressive']) {
    +      if ($batch['progressive'] ?? NULL) {
    

    This as well because it's unclear how this is not set.

  8. +++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
    @@ -126,7 +126,7 @@ protected function validateNode(TypedDataInterface $data, $constraints = NULL, $
    -    $property_path = $is_root_call ? '' : PropertyPath::append($previous_path, $data->getName());
    +    $property_path = $is_root_call ? '' : PropertyPath::append((string) $previous_path, (string) $data->getName());
    

    @mondarke any idea about this one>? What test causes it?

  9. +++ b/core/modules/config/src/Form/ConfigImportForm.php
    @@ -126,7 +126,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    -        $archiver = new ArchiveTar($path, 'gz');
    +        $archiver = new ArchiveTar($path);
    

    This change is not needed anymore.

  10. +++ b/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
    @@ -181,7 +181,7 @@ public function prepareRow(Row $row) {
    -    $row->setSourceProperty('field_settings', $field_data['settings']);
    +    $row->setSourceProperty('field_settings', $field_data['settings'] ?? NULL);
    

    Same here.

  11. +++ b/core/modules/locale/locale.bulk.inc
    @@ -385,12 +385,14 @@ function locale_translate_batch_finished($success, array $results) {
             foreach ($results['stats'] as $filepath => $report) {
    -          $additions += $report['additions'];
    -          $updates += $report['updates'];
    -          $deletes += $report['deletes'];
    -          $skips += $report['skips'];
    -          if ($report['skips'] > 0) {
    -            $skipped_files[] = $filepath;
    +          if (is_array($report)) {
    +            $additions += $report['additions'];
    +            $updates += $report['updates'];
    +            $deletes += $report['deletes'];
    +            $skips += $report['skips'];
    +            if ($report['skips'] > 0) {
    +              $skipped_files[] = $filepath;
    +            }
               }
    

    It's be good to understand how $report is not as expected.

  12. +++ b/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
    @@ -152,7 +152,7 @@ public function testLocaleTranslationJsDependencies() {
         // Calculate the filename of the JS including the translations.
         $js_translation_files = \Drupal::state()->get('locale.translation.javascript');
    -    $js_filename = $prefix . '_' . $js_translation_files[$prefix] . '.js';
    +    $js_filename = $prefix . '_' . ($js_translation_files[$prefix] ?? '') . '.js';
    

    This is very smelly I'm not sure that \Drupal\Tests\locale\Functional\LocaleJavascriptTranslationTest::testLocaleTranslationJsDependencies is testing what we think it is. Yep adding $this->assertRaw($js_filename); to the test shows that this test is not working as we think it is. We need to file a separate issue to fix this properly.

  13. +++ b/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php
    @@ -70,7 +70,7 @@ public function prepareRow(Row $row) {
    -    $row->setSourceProperty($other_property . '_translated', $results['translation']);
    +    $row->setSourceProperty($other_property . '_translated', $results['translation'] ?? NULL);
    

    @mondrake do you know which test this was for?

mondrake’s picture

Can't remember them all, so I reverted #90.1, 4, 5, 6, 7, 8, 9, 10, 11 and 13 in #3065023-90: Ignore, testing issue, and will report back on the basis of the results there.

alexpott’s picture

Berdir’s picture

#90.1 It probably already is an Attributes object in some cases?

See https://3v4l.org/B4ZhS, that apparently was deprecated in PHP 7.4 (only in beta1+ in fact..)

mondrake’s picture

#90.1: yes, sometimes $variables['attributes'] is an object, and array functions do not operate on ArrayObjects (see #3087602-8: DeprecatedArray implements \ArrayAccess, traversals not possible and 9. The current fix is not secure, either. I would suggest to do this, instead

index d2d54979b7..f1bfe697c4 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -817,9 +817,9 @@ function template_preprocess_image(&$variables) {
 
   foreach (['width', 'height', 'alt', 'title', 'sizes'] as $key) {
     if (isset($variables[$key])) {
-      // If the property has already been defined in the attributes,
-      // do not override, including NULL.
-      if (array_key_exists($key, $variables['attributes'])) {
+      // If the property has already been defined in the attributes, do not
+      // override, including NULL. Attributes can be an array or an object.
+      if ((is_array($variables['attributes']) && array_key_exists($key, $variables['attributes'])) || (is_object($variables['attributes']) && property_exists($variables['attributes'], $key))) {
         continue;
       }
       $variables['attributes'][$key] = $variables[$key];

#90.8: this is basically breaking ALL the Functional and FunctionalJavascript tests with something like this:

7) Drupal\Tests\file\Functional\FileFieldAnonymousSubmissionTest::testAnonymousNodeWithFile
Trying to access array offset on value of type int

/home/travis/drupal8/vendor/symfony/validator/Util/PropertyPath.php:40
/home/travis/drupal8/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php:130
/home/travis/drupal8/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php:159
/home/travis/drupal8/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php:100
/home/travis/drupal8/core/lib/Drupal/Core/TypedData/Validation/RecursiveValidator.php:90
/home/travis/drupal8/core/lib/Drupal/Core/TypedData/TypedData.php:132
/home/travis/drupal8/core/modules/user/user.module:291
/home/travis/drupal8/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php:267
/home/travis/drupal8/core/lib/Drupal/Core/Form/FormValidator.php:82
/home/travis/drupal8/core/lib/Drupal/Core/Form/FormValidator.php:275
/home/travis/drupal8/core/lib/Drupal/Core/Form/FormValidator.php:118
/home/travis/drupal8/core/lib/Drupal/Core/Form/FormBuilder.php:577
/home/travis/drupal8/core/lib/Drupal/Core/Form/FormBuilder.php:487
/home/travis/drupal8/core/includes/install.core.inc:971
/home/travis/drupal8/core/includes/install.core.inc:625
/home/travis/drupal8/core/includes/install.core.inc:578
/home/travis/drupal8/core/includes/install.core.inc:117
/home/travis/drupal8/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php:296
/home/travis/drupal8/core/tests/Drupal/Tests/BrowserTestBase.php:569
/home/travis/drupal8/core/tests/Drupal/Tests/BrowserTestBase.php:402
/home/travis/drupal8/core/modules/file/tests/src/Functional/FileFieldTestBase.php:48
/home/travis/drupal8/core/modules/file/tests/src/Functional/FileFieldAnonymousSubmissionTest.php:20

More to come...

alexpott’s picture

Issue summary: View changes

Filed upstream fix for #90.8 - see https://github.com/symfony/symfony/pull/34097

Ghost of Drupal Past’s picture

What about adding

if (!$variables['attributes'] instanceof Attribute) {
  if (!is_array($variables['attributes'])) {
    $variables['attributes'] = [$variables['attributes']];
  }
  $variables['attributes'] = new Attribute($variables['attributes']);
}

No more guessing whether it's array or object.

mondrake’s picture

Assigned: Unassigned » mondrake

Full details in #3065023-92: Ignore, testing issue.

Maybe some of the other fixes were transient and are no longer needed.
I am working on an updated patch with findings so far, will test there and then post here once green.

#90.4: this and several other migrate_drupal_ui tests

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\migrate_drupal_ui\Functional\d6\MultilingualReviewPageTest
E                                                                   1 / 1 (100%)

Time: 55 seconds, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\migrate_drupal_ui\Functional\d6\MultilingualReviewPageTest::testMigrateUpgradeReviewPage
Trying to access array offset on value of type null

/var/www/html/core/lib/Drupal/Core/Database/Install/Tasks.php:247
/var/www/html/core/lib/Drupal/Core/Database/Driver/mysql/Install/Tasks.php:146
/var/www/html/core/modules/migrate_drupal_ui/tests/src/Functional/MultilingualReviewPageTestBase.php:108
/var/www/html/core/modules/migrate_drupal_ui/tests/src/Functional/MultilingualReviewPageTestBase.php:51

ERRORS!
Tests: 1, Assertions: 4, Errors: 1.

#90.5:

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\KernelTests\Core\Field\FieldMissingTypeTest
EE                                                                  2 / 2 (100%)

Time: 3.51 seconds, Memory: 4.00 MB

There were 2 errors:

1) Drupal\KernelTests\Core\Field\FieldMissingTypeTest::testFieldStorageMissingType
Trying to access array offset on value of type null

/var/www/html/core/lib/Drupal/Core/Field/FieldTypePluginManager.php:172
/var/www/html/core/modules/field/src/FieldStorageConfigStorage.php:168
/var/www/html/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php:193
/var/www/html/core/lib/Drupal/Core/Entity/EntityStorageBase.php:300
/var/www/html/core/lib/Drupal/Core/Entity/EntityBase.php:542
/var/www/html/core/modules/field/field.module:182
/var/www/html/core/lib/Drupal/Core/Extension/ModuleHandler.php:392
/var/www/html/core/lib/Drupal/Core/Entity/EntityFieldManager.php:572
/var/www/html/core/lib/Drupal/Core/Entity/EntityFieldManager.php:448
/var/www/html/core/modules/field/src/Entity/FieldConfig.php:296
/var/www/html/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:1241
/var/www/html/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:524
/var/www/html/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:449
/var/www/html/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:415
/var/www/html/core/lib/Drupal/Core/Entity/EntityStorageBase.php:300
/var/www/html/core/lib/Drupal/Core/Entity/EntityStorageBase.php:250
/var/www/html/core/lib/Drupal/Core/Entity/EntityBase.php:532
/var/www/html/core/tests/Drupal/KernelTests/Core/Field/FieldMissingTypeTest.php:74

#90.7:

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\system\Functional\Batch\ProcessingTest
.....E..                                                            8 / 8 (100%)

Time: 1.7 minutes, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\system\Functional\Batch\ProcessingTest::testBatchFormProgrammatic
Exception: Notice: Trying to access array offset on value of type null
Drupal\Core\Form\FormSubmitter->doSubmitForm()() (Line: 65)


/var/www/html/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php:51
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:203
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:156
/var/www/html/vendor/guzzlehttp/promises/src/TaskQueue.php:47
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:246
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:223
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:267
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:225
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:62
/var/www/html/vendor/guzzlehttp/guzzle/src/Client.php:131
/var/www/html/vendor/fabpot/goutte/Goutte/Client.php:180
/var/www/html/vendor/symfony/browser-kit/Client.php:318
/var/www/html/vendor/behat/mink-browserkit-driver/src/BrowserKitDriver.php:144
/var/www/html/vendor/behat/mink/src/Session.php:148
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:326
/var/www/html/core/modules/system/tests/src/Functional/Batch/ProcessingTest.php:145

ERRORS!
Tests: 8, Assertions: 70, Errors: 1.

#90.11: this and other locale tests

PHPUnit 7.5.16 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\locale\Functional\LocaleImportFunctionalTest
EEEEEE                                                              6 / 6 (100%)

Time: 1.12 minutes, Memory: 4.00 MB

There were 6 errors:

1) Drupal\Tests\locale\Functional\LocaleImportFunctionalTest::testStandalonePoFile
Exception: Notice: Trying to access array offset on value of type int
locale_translate_batch_finished()() (Line: 388)


/var/www/html/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php:51
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:203
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:156
/var/www/html/vendor/guzzlehttp/promises/src/TaskQueue.php:47
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:246
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:223
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:267
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:225
/var/www/html/vendor/guzzlehttp/promises/src/Promise.php:62
/var/www/html/vendor/guzzlehttp/guzzle/src/Client.php:131
/var/www/html/vendor/fabpot/goutte/Goutte/Client.php:180
/var/www/html/vendor/symfony/browser-kit/Client.php:318
/var/www/html/vendor/behat/mink-browserkit-driver/src/BrowserKitDriver.php:144
/var/www/html/vendor/behat/mink/src/Session.php:148
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:326
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:532
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:333
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:532
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:106
/var/www/html/core/tests/Drupal/Tests/UiHelperTrait.php:209
/var/www/html/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php:384
/var/www/html/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php:71
mondrake’s picture

#96

if (!is_array($variables['attributes'])) {
    $variables['attributes'] = [$variables['attributes']];
  }

can $variables['attributes'] be a scalar here?

alexpott’s picture

#96/@Charlie ChX Negyesi this is has caused major headaches before - digging in the issue queue... something was an array at the start the render pipeline and then depending on if a module was enabled it became an Attribute object - making life hard for template_preprocess_functions in contrib and custom.

alexpott’s picture

@mondrake great work! Thanks for doing this - and also doing it in a testing issue is smart.

alexpott’s picture

+++ b/core/lib/Drupal/Core/Form/FormSubmitter.php
@@ -61,7 +61,7 @@ public function doSubmitForm(&$form, FormStateInterface &$form_state) {
       $batch['progressive'] = !$form_state->isProgrammed();
       $response = batch_process();
-      if ($batch['progressive']) {
+      if ($batch['progressive'] ?? NULL) {

Debugged the failing test \Drupal\Tests\system\Functional\Batch\ProcessingTest::testBatchFormProgrammatic(). This should be

// If the batch has been completed and _batch_finished() called then $batch will be NULL.
if ($batch && $batch['progressive']) {

Using null coalescence here could hide errors caused by a batch doing soemthing very odd and unsetting $batch['progressive'].

mondrake’s picture

#101 ok will put in an incoming patch in the testing issue

mondrake’s picture

So here's an updated patch with more todos referrring to latest comments.

EDIT - ouch, the todos are in the interdiff but not in the patch... will correct in next one.

mondrake’s picture

#90.2 if $css_asset is empty, which is the case in some render tests, this fails. Throwing the exception because this is what happens a few lines below if the asset type is not recognised. Yes, it should be split in a separate issue. Added a @todo.

#90.3 I went for an inline check that the version is a string. Casting generally to string before entering in the checks may be fragile: a version number could be interpreted as a float and we never know what the casted string may become (think 1.1 and 1.10, same 'number' but totally different 'version').

Added todos that went missing in #103.

alexpott’s picture

+++ b/core/includes/theme.inc
@@ -817,9 +817,9 @@ function template_preprocess_image(&$variables) {
-      // If the property has already been defined in the attributes,
-      // do not override, including NULL.
-      if (array_key_exists($key, $variables['attributes'])) {
+      // If the property has already been defined in the attributes, do not
+      // override, including NULL. Attributes can be an array or an object.
+      if ((is_array($variables['attributes']) && array_key_exists($key, $variables['attributes'])) || (is_object($variables['attributes']) && property_exists($variables['attributes'], $key))) {
         continue;

This fix isn't right unfortunately.

>>> $a = new \Drupal\Core\Template\Attribute(['foo' => NULL, 'bar' => 'bar']);
=> Drupal\Core\Template\Attribute {#4861
     markup: " bar="bar"",
   }
>>> $a->toArray();
=> [
     "foo" => null,
     "bar" => "bar",
   ]
>>> property_exists($a, 'foo');
=> false
>>> property_exists($a, 'bar');
=> false
>>> isset($a['foo']);
=> true
>>> isset($a['bar']);
=> true
>>> isset($a['width']);
=> false
>>> isset($a->toArray()['foo']);
=> false

So I think this should be we need to detect if we dealing with an array() or an Attribute object. And if we're dealing with an attribute object use isset() - which is super funky because it works different from arrays. Anyhow I think this is a good candidate for splitting out into a separate issue and getting test coverage as the current code in HEAD is broken too...

>>> array_key_exists('foo', $a)
=> false
>>> array_key_exists('bar', $a)
=> false

lolz.

mondrake’s picture

Assigned: Unassigned » mondrake

Sorry I lost some bits in #103 and #104. Will fix now.

alexpott’s picture

Re arrays vs attribute objects @lauriii dug out #2917653: toolbar_preprocess_html() converts attributes from array to Attribute object - see how much fun!!!

mondrake’s picture

Re-added the coalesce operators in core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php and core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php, and re #105 reverted to the hack in #89, adding a @todo to signal the need of a separate issue.

alexpott’s picture

  1. +++ b/core/includes/theme.inc
    @@ -815,13 +815,23 @@ function template_preprocess_image(&$variables) {
    +  // Ensure that attributes can be accessed as an array, for PHP 7.4
    +  // compatibility.
    +  if ($variables['attributes'] instanceof Attribute) {
    +    $attributes_array = $variables['attributes']->toArray();
    +  }
    +  elseif (is_array($variables['attributes'])) {
    +    $attributes_array = $variables['attributes'];
    +  }
    +  else {
    +    $attributes_array = [];
    +  }
    

    This will work. I wonder if it is worth putting this as a static help on the Attributes object. Also this is not only about PHP7.4...

  2. +++ b/core/includes/theme.inc
    @@ -815,13 +815,23 @@ function template_preprocess_image(&$variables) {
    -      // @todo the cast to array below is needed to get tests pass on PHP 7.4,
    -      // but requires a separate issue to fix.
    -      if (array_key_exists($key, (array) $variables['attributes'])) {
    +      if (array_key_exists($key, $attributes_array)) {
    

    This code is broken on all versions of PHP when $variable['attributes'] is an Attribute object.

    But yeah a separate issue with tests etc is the way to go here.

mondrake’s picture

I wonder if it is worth putting this as a static help on the Attributes object

Then maybe all we need here is a Attribute::getKeys method to return the defined keys, regardless if array or object and set or null: that’s the problem at hand. Once you know the key, accessing it via array syntax is ok.

mondrake’s picture

fwiw I tried to find the instances where array functions are called with $variables['attributes'] as an argument

grep -r -e "rray.*\$v[^\[]*\[\'attributes\'\][^\[]" .

and all I could find was

./core/includes/theme.inc:      if (array_key_exists($key, $variables['attributes'])) {
./core/includes/theme.inc:      $variables['attributes'] = NestedArray::mergeDeep($variables['attributes'], $variables[$key]['#attributes']);
./core/includes/theme.inc:    $variables['attributes'] = NestedArray::mergeDeep($variables['attributes'], (array) $element['#items'][0]->_attributes);
Ghost of Drupal Past’s picture

mergeDeep is a special kind of trouble. It passes arguments to mergeDeepArrays which doesn't fatal on as long as the "array" is iterable but if the iterable contains ArrayAccess objects instead of arrays then the recursion breaks! Congratulations on finding a really ugly bug. I mean... https://3v4l.org/X5Cje

mondrake’s picture

mondrake’s picture

@Charlie ChX Negyesi let's say I found the call and you found the bug :)

Do we need to file a separate critical issue 'Ensure that mixing array and Attribute objects in theme rendering is managed properly'?

mondrake’s picture

mondrake’s picture

Very strange results in PHP 7.4 tests in #104... we have an intermittent deprecation failure (!). No clue.

mondrake’s picture

An hopefully better solution for #90.5.

Since we are calling ::getDefinition($type, FALSE), exception throwing on invalid plugin is disabled, and $plugin_definition will be NULL. So just intercepting that and making sure the 'class' key exists in the array.

alexpott’s picture

+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -168,10 +168,8 @@ public function getPreconfiguredOptions($field_type) {
     $plugin_definition = $this->getDefinition($type, FALSE);
-    // @todo the use of the coalesce operator below is needed to get
...
-    // PHP 7.4.
-    return $plugin_definition['class'] ?? NULL;
+    $plugin_class = ($plugin_definition && isset($plugin_definition['class'])) ? $plugin_definition['class'] : NULL;
+    return $plugin_class;

I think the null coalescence here is okay... but what is worth doing is adding a comment that plugin_definition can be null if the plugin does not exist. And we should adjust the return type docs...

Hmmm... actually this introduces a behaviour change. Atm in HEAD if $plugin_definition is an array then it will produce an error. So maybe

    try {
      $plugin_definition = $this->getDefinition($type);
    }
    catch (PluginNotFoundException $e) {
      return NULL;
    }

The other option would be to throw the exception and catch it and re-throw because the failing test is \Drupal\KernelTests\Core\Field\FieldMissingTypeTest and that's testing exceptions are thrown. Perhaps yet-another-sub-issue to discuss this?

mondrake’s picture

mondrake’s picture

Issue summary: View changes
voleger’s picture

re #117 yes, php 7.4 introduce some deprecations.
See "Implode with historical parameter order" at https://www.php.net/manual/en/migration74.deprecated.php

mondrake’s picture

@voleger yes the point here is that the same patch first failed with a deprecation yesterday, and later passed with no error. Pretty weird

alexpott’s picture

Issue summary: View changes

Pushed an upstream fix for the vfsStream - https://github.com/bovigo/vfsStream/pull/204 for their 1.x branch.

mondrake’s picture

symfony/validator and vfsStream upstream PRs were merged, but no releases yet. Adjusting to requiring most current dev branches to see status.

Also, added back todos for #119 and #120.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Assigned: Unassigned » mondrake

mikey179/vfsstream 1.6.8 was just released

mondrake’s picture

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

mondrake’s picture

symfony/validator 3.4.33 and composer/composer 1.9.1 are out and we'll need those for the issue at hand here.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Updated patch to reflect new releases of dependencies and symfony/validator updated already to 3.4.33

effulgentsia’s picture

+++ b/core/includes/install.core.inc
@@ -2323,7 +2323,9 @@ function install_config_import_batch() {
   $system_site = $sync->read('system.site');
-  \Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'])->save();
+  if ($system_site !== FALSE) {
+    \Drupal::configFactory()->getEditable('system.site')->set('uuid', $system_site['uuid'])->save();
+  }

Can we open a separate issue for this to discuss it further? It seems to me that we should likely do something when system.site doesn't exist. Maybe throw an exception? Or return from the function early? Or at least add a comment for why doing nothing and continuing with the rest of the function is correct?

mondrake’s picture

Added a @todo for #137, removed composer update of vfsStream (just updated in HEAD), removed composer self-update as it looks like the PHP 7.4 container is already on 1.9.1.

mondrake’s picture

xjm’s picture

Issue tags: +8.8.0 release notes

We'll want to mention this in the release notes (either that it's supported by the time it ships, or that there are a few compatibility issues remaining). For beta1 I'm going to list it in the "known issues" section.

mondrake’s picture

mondrake’s picture

alexpott’s picture

It'd be awesome if someone could review #2830631: Remove code that tries to use _raw_variables for route argument resolution as it does not work

Re #137 we already have explicit testing of what happens in both a config install and a config import when core.extension is missing - that's why we're getting these errors - they're being triggered by the test coverage. See \Drupal\KernelTests\Core\Config\ConfigImporterTest::testEmptyImportFails(), \Drupal\KernelTests\Core\Config\ConfigImporterTest::testSiteUuidValidate() and \Drupal\FunctionalTests\Installer\InstallerExistingConfigNoConfigTest

mondrake’s picture

xmacinfo’s picture

Issue summary: View changes

Changed to:
PHP 7.4 is due to be released in November 28, 2019, a week before Drupal 8.8.0.

mondrake’s picture

amateescu’s picture

+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -168,7 +168,10 @@ public function getPreconfiguredOptions($field_type) {
+    // @todo below is needed to get FieldMissingTypeTest tests pass on PHP
+    // 7.4. Better solution needed.
+    $plugin_class = ($plugin_definition && isset($plugin_definition['class'])) ? $plugin_definition['class'] : NULL;
+    return $plugin_class;

Opened #3095895: FieldTypePluginManager::getPluginClass() should throw an exception when called for a field type that doesn't exist for this part.

mondrake’s picture

amateescu’s picture

Gábor Hojtsy’s picture

Issue tags: +Needs release note
heddn’s picture

Issue summary: View changes
mondrake’s picture

There's not a point release for easyrdf/easyrdf yet, but dev-master was updated yesterday on Packagist, including https://github.com/njh/easyrdf/pull/311.

Let's see if updating to dev-master can help removing the workaround introduced in #79.

Status: Needs review » Needs work

The last submitted patch, 153: 3086374-153.patch, failed testing. View results

mondrake’s picture

Adding aliases to allow both old- and new-school class names for easyrdf

mondrake’s picture

Status: Needs work » Needs review
Liam Morland’s picture

Title: Make Drupal 8.8 compatible with PHP 7.4 » Make Drupal 8 compatible with PHP 7.4
mondrake’s picture

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: +Needs reroll
ravi.shankar’s picture

Status: Needs work » Needs review
FileSize
34.39 KB

I have added re-roll of patch #155.

mondrake’s picture

Issue summary: View changes
Status: Needs review » Needs work
Spokje’s picture

Status: Needs work » Needs review
xmacinfo’s picture

Status: Needs review » Needs work

Marked by as Needs work based on bot results. Thanks.

Spokje’s picture

Status: Needs work » Needs review

To Be Honest: I don't really understand why is failing on TestBot.
It passes on my local machine and the patch for this issue doesn't (seem to) do anything with/to it?

Let's await the arrival of Bigger Brains, because mine can't grasp it all.

Spokje’s picture

Status: Needs review » Needs work

(Meh, didn't refresh the page, so my status was still on NR, put it back on NW now)

mondrake’s picture

The weird thing is that #163 failed, while #161 just a few hours earlier didn't, and I cannot see any change in between that would have affected the results. It is as if PHP 7.4-dev just started behave differently.

Liam Morland’s picture

The failures look more like issues with the testing environment.

Gábor Hojtsy’s picture

timmillwood’s picture

Status: Needs review » Needs work
  1. +++ b/core/composer.json
    @@ -37,7 +37,7 @@
    +        "easyrdf/easyrdf": "^0.9 || dev-master",
    
    +++ b/core/drupalci.yml
    @@ -15,6 +15,10 @@ build:
    +          - "sudo -u www-data /usr/local/bin/composer require easyrdf/easyrdf:dev-master --no-progress"
    

    I wonder if there's anything we can do to work with the easyrdf community.

  2. +++ b/core/includes/install.core.inc
    @@ -2322,7 +2322,11 @@ function install_config_import_batch() {
    +  // @todo the conditional below is required to get tests pass on PHP 7.4;
    +  // find a better solution.
    +  if ($system_site !== FALSE) {
    

    Can we open an issue for this todo? Also explain the cases when $system_site might be false as it will give someone a head start coming to this.

  3. +++ b/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
    @@ -49,6 +49,11 @@ public function render(array $css_assets) {
    +      // @todo the emptiness check below is needed to get tests pass on
    +      // PHP 7.4. Needs better solution.
    +      if (empty($css_asset)) {
    

    Can we open an issue for this todo?

  4. +++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
    @@ -243,7 +243,9 @@ public function getFormOptions(array $database) {
    +    // @todo the use of the coalesce operator below is needed to get
    +    // migrate_drupal_ui tests pass on PHP 7.4.
    +    $profile = $install_state['parameters']['profile'] ?? NULL;
    

    Can we open an issue for this @todo?

  5. +++ b/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
    @@ -181,7 +181,9 @@ public function prepareRow(Row $row) {
    +    // @todo the use of the coalesce operator below is needed to get
    +    // migrate tests pass on PHP 7.4.
    +    $row->setSourceProperty('field_settings', $field_data['settings'] ?? NULL);
    

    Can we open an issue for this todo?

  6. +++ b/core/modules/locale/locale.bulk.inc
    @@ -385,12 +385,16 @@ function locale_translate_batch_finished($success, array $results) {
    +          // @todo is_array check below is needed to get locale tests pass on
    +          // PHP 7.4.
    +          if (is_array($report)) {
    

    Sorry, same, issue for this todo please.

  7. +++ b/core/modules/rdf/rdf.module
    @@ -10,6 +10,16 @@
    + * @todo remove in Drupal 9.
    

    Is this the standard way to denote sections of code to remove in D9?

  8. +++ b/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php
    @@ -70,7 +70,9 @@ public function prepareRow(Row $row) {
    +    // @todo the use of the coalesce operator below is needed to get
    +    // migrate tests pass on PHP 7.4.
    +    $row->setSourceProperty($other_property . '_translated', $results['translation'] ?? NULL);
    

    Sorry, another, issue for @todo.

  9. +++ b/core/modules/taxonomy/tests/src/Kernel/Views/ArgumentValidatorTermTest.php
    @@ -61,6 +61,10 @@ public function testArgumentValidatorTerm() {
    +    // @todo $view->argument['tid']->validator should be defined, but it's not
    +    // here and that's leading to test failures in PHP 7.4. Figure out a more
    +    // robust solution rather than creating the stdClass object in the test.
    +    $view->argument['tid']->validator = new \stdClass();
    

    and another.

  10. +++ b/core/modules/views/src/Plugin/views/filter/Date.php
    @@ -182,7 +182,10 @@ protected function opBetween($field) {
    +    // @todo $this->value['value'] should always be defined, but it's not
    +    // and that's leading to test failures in PHP 7.4. Figure out a more
    +    // robust solution rather than coalescing to NULL.
    +    $value = intval(strtotime($this->value['value'] ?? NULL, 0));
    

    and another

  11. +++ b/core/modules/views/src/Plugin/views/filter/NumericFilter.php
    @@ -354,7 +354,10 @@ protected function opBetween($field) {
    +    // @todo $this->value['value'] should always be defined, but it's not
    

    Lets just open issue for all todos.

alexpott’s picture

@timmillwood progress has stalled here somewhat but these things are supposed to be solved here and not in follow-ups ie. the @todo's are for this issue.

alexpott’s picture

mondrake’s picture

alexpott’s picture

Version: 8.9.x-dev » 9.0.x-dev
Status: Needs work » Needs review
FileSize
41.51 KB

x-post with #175 but I think this represents the path forward...

This patch adds back the class alias solution for \EasyRdf_ParsedUri as since #3090017: Isolate test dependency on easyrdf/easyrdf to a single trait we can do this in test-only code in a way that only impacts the test system. Hopefully easyrdf/easyrdf will do a release and we can upgrade to it sometime. However rather than move to dev-master and make life difficult for any contrib modules using that vendor library we can take the least disruptive path for both Drupal 9 and 8.x at this point.

Now we need to focus on the rest of the @todos in Drupal 9.0.x and then focus on backporting to 8.x

alexpott’s picture

alexpott’s picture

Here's a patch with all the @todo's remove other than those that are linked to a specific test or are in a test. This should fail on PHP 7.4 - but let's not add any @todo's back in unless they are linked to either a specific test that can re-create the error or linked to an issue to resolve once this has landed (hopefully we have none of these).

alexpott’s picture

Title: Make Drupal 8 compatible with PHP 7.4 » Make Drupal 8 & 9 compatible with PHP 7.4
alexpott’s picture

So I think fixing the @todo in \Drupal\hal\Normalizer\EntityReferenceItemNormalizer::normalize() is out-of-scope. Using the null coalesce operator we've made it behave the same as PHP 7.3 so opened #3110815: \Drupal\hal\Normalizer\EntityReferenceItemNormalizer::normalize() tries to normalize entities that don't exist to fix that code properly because it is not doing what it is supposed to for entity references pointing to values that don't exist.

Patch attached also fixes \Drupal\Tests\taxonomy\Kernel\Views\ArgumentValidatorTermTest - that test was not testing what it thought it was. Now it is properly testing what happens when the validator doesn't allow multiple terms.

mondrake’s picture

alexpott’s picture

One down...

diff --git a/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php b/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
index 74340884d2..e15fe7bdc6 100644
--- a/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
+++ b/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
@@ -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);
   }
 

So this one is fun... the source property 'field_data' has never existed so this sets a source property up of 'field_settings' but it is always equal to NULL. It's completely pointless. The field settings are there - they are in 'data' property.

heddn’s picture

If it truly is NULL, then I don't have any concerns. Although BC could be effected, it seems like a small edge case. Considering its really hard to take over the field instance migration from core. No one really does. So +1.

alexpott’s picture

This should fix the remaining kernel tests. Now for the functional...

alexpott’s picture

Fixing the last fail - again it is a test expectation gone wrong.

alexpott’s picture

+++ b/core/lib/Drupal/Core/Config/StorageComparer.php
@@ -388,7 +388,7 @@ public function hasChanges() {
   public function validateSiteUuid() {
     $source = $this->sourceStorage->read('system.site');
     $target = $this->targetStorage->read('system.site');
-    return $source['uuid'] === $target['uuid'];
+    return $source && $target && $source['uuid'] === $target['uuid'];
   }

+++ b/core/modules/language/src/LanguageServiceProvider.php
@@ -87,9 +87,11 @@ protected function isMultilingual() {
     $system = $config_storage->read('system.site');
-    $default_language = $config_storage->read(static::CONFIG_PREFIX . $system['default_langcode']);
-    if (is_array($default_language)) {
-      return $default_language;
+    if ($system) {

I think we need to add comments for these changes to explain why they are necessary and the situations they deal with.

Gung Wang’s picture

Title: Make Drupal 8 & 9 compatible with PHP 7.4 » Tons of PHP notices: Drupal 8.8.1 on PHP 7.4.1
Version: 9.0.x-dev » 8.8.1
Category: Task » Bug report
Issue summary: View changes
Priority: Critical » Normal
Issue tags: -8.8.0 release notes, -Needs release note +Drupal 8.8.1

I got a ton of PHP Notices on my local site:

It might be a compatible problem of Drupal 8.8.1 with PHP 7.4.1

Notice: Trying to access array offset on value of type int in Drupal\Core\Render\Element::children() (line 81 of core\lib\Drupal\Core\Render\Element.php). 
Notice: Trying to access array offset on value of type null in Drupal\Component\Annotation\Doctrine\DocParser->Identifier() (line 969 of core\lib\Drupal\Component\Annotation\Doctrine\DocParser.php). 
 

My tempery solution is to change the code below:

#  docroot/core/lib/Drupal/Core/Render/Element.php:: children() => line 81
# if ($key === '' || $key[0] !== '#') 
if ($key === '' || empty($key[0]) || $key[0] !== '#') 
alexpott’s picture

heddn’s picture

Issue tags: -PHP 7.4
alexpott’s picture

Category: Task » Bug report
Issue tags: +PHP 7.4

@Gung Wang I've reverted your changes to the issue summary and issue metadata. The fact that Drupal 8 is not compatible was mentioned in the known issues of the release note for 8.8.0.

I do however agree with you that this has now become a bugfix as PHP 7.4 has been a stable release of PHP since late last year.

alexpott’s picture

Adding a comment as per #187.

For the \Drupal\language\LanguageServiceProvider::getDefaultLanguageValues() change - I've reverted that change as I want to work out why that is needed.

alexpott’s picture

Okay now I've added a comment to \Drupal\language\LanguageServiceProvider::getDefaultLanguageValues(). I tried to set up the configuration in KTB but this wasn't enough either. I think making the change in \Drupal\language\LanguageServiceProvider::getDefaultLanguageValues() is ok. Not ideal but better than other larger scale changes to the test system.

alexpott’s picture

Issue summary: View changes
Issue tags: -Needs release note

Updated the issue summary to reflect the recent progress and solution.

I think this is just about ready so reviews very welcome!

joseph.olstad’s picture

retriggered postgresql 9 / on php 7.3 tests
just to see if it was a runner glitch, otherwise might have to look closer at the 3 errors.

alexpott’s picture

Ah still didn't get the NumericFilter value quite right... patch attached fixes postgresql and doesn't break the other db drivers.

Gábor Hojtsy’s picture

Changes look good on a cursory look but I did not scrutinise them. Here are three things I found nonetheless:

  1. +++ b/core/lib/Drupal/Core/Config/StorageComparer.php
    @@ -388,7 +388,9 @@ public function hasChanges() {
    +    // configuraion. In such cases the site UUID cannot be valid.
    

    Configuraion typo

  2. +++ b/core/lib/Drupal/Core/Routing/CompiledRoute.php
    @@ -143,23 +143,22 @@ public function getRequirements() {
       /**
        * {@inheritdoc}
        */
    ...
       /**
        * {@inheritdoc}
        */
    

    Is __serialize() and __unserialize() like __sleep() and __wakeup()? I tried finding docs but could not.

    Should these not be inheritdoc at this point now that they implement internal PHP magic?

  3. +++ b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    @@ -0,0 +1,349 @@
    + * This is copy of \EasyRdf_ParsedUri from the easyrdf/easyrdf library.
    + *
    + * It fixes a PHP 7.4 deprecation in \EasyRdf_ParsedUri::normalise().
    + */
    

    Can we link to the upstream issue here for future checking if that got fixed, etc.

mondrake’s picture

+++ b/core/lib/Drupal/Component/Annotation/Doctrine/DocParser.php
@@ -966,13 +966,16 @@ private function Identifier()
-        while ($this->lexer->lookahead['position'] === ($this->lexer->token['position'] + strlen($this->lexer->token['value']))
+        $position = $this->lexer->lookahead['position'] ?? NULL;
+        while ($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);
 
             $className .= '\\' . $this->lexer->token['value'];
+
+            $position = $this->lexer->lookahead['position'] ?? NULL;
         }
 

looking at how Doctrine is now doing that

        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);

            $className .= '\\' . $this->lexer->token['value'];
        }

maybe we do not need doing the second assignment to $position, that I was adding earlier in the patches here only to be on the safe side.

longwave’s picture

> Is __serialize() and __unserialize() like __sleep() and __wakeup()? I tried finding docs but could not.

Yes, this is new in PHP 7.4: https://wiki.php.net/rfc/custom_object_serialization

alexpott’s picture

Thanks for the review @Gábor Hojtsy

1. Fixed.
2. See https://wiki.php.net/rfc/custom_object_serialization - this was implement upstream so we have to follow suit. We have to make this change due to changes in Symfony 4 - see https://github.com/symfony/symfony/commit/5638d6adcc95a0bdc757e70d10c1ad...
3. It is fixed upstream - but they need to do a release - https://github.com/njh/easyrdf/pull/311 - not really sure what to link to. I've create another Drupal issue to track future options.

alexpott’s picture

Re #198 - good idea we should copy doctrine here because it make applying any future changes simpler. Note that this class does not conform to Drupal's coding standards because it is basically a copy of Doctrine's code.

Also Doctrine has not done the change to \Drupal\Component\Annotation\Doctrine\DocParser::Value() so I'm reverting that to work out why it is needed.

mondrake’s picture

There are no testbots for PHP 7.4 on SQLite and PostgreSQL :(

alexpott’s picture

@mondrake I'm pretty sure that that doesn't matter too much - and shouldn't prevent us getting this in. I've run many of the tests locally that failed on postgres and sqlite so we know that nothing major is trigger notices in the db drivers.

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Then I think this is ready, at least for D9. Follow-ups are created and referenced. Tests pass on 7.4-dev on MySQL. Hopefully this in could trigger setup of testbots on a PHP 7.4 point release and for all the dbs.

alexpott’s picture

+++ b/core/modules/rdf/src/Entity/RdfMapping.php
@@ -148,7 +148,9 @@ public function calculateDependencies() {
+    if (!empty($bundle_config_dependency)) {
+      $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']);
+    }

This change is due to incorrect mocking in \Drupal\Tests\rdf\Unit\RdfMappingConfigEntityUnitTest. \Drupal\Core\Entity\EntityType::getBundleConfigDependency() can never return NULL. We should fix the test instead.

As this moves the changes from runtime to test time I don't think this affects the rtbc status.

mondrake’s picture

+++ b/core/lib/Drupal/Core/Routing/CompiledRoute.php
@@ -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 is Symfony4 as per #200, and is obviously causing lot of failures when this patch is applied to D8.9. So the backport will have to be adjusted for Symfony3.

alexpott’s picture

@mondrake yeah that is Symfony 4 only code - and there are other things too that'll need to be fixed in 8.9.x. I suggest that once this lands in 9.0.x we get to work on 8.9.x (and 8.8.x).

Re #205 I've filed #3111029: RdfMapping unnecessarily adds a dependency on the module providing the target entity as a related follow-up - though not necessary for PHP7.4 or even a bug fix - just neater and less redundant code.

catch’s picture

  1. +++ b/core/includes/install.core.inc
    @@ -2292,7 +2292,12 @@ function install_config_import_batch() {
       $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 then the error will cause
    +  // a ConfigImporterException and configuration import will fail.
    +  if ($system_site !== FALSE) {
    

    Comment nit: is the error that the system.site config is not there, or the ConfigImporterException itself? I would assume the error is the exception getting thrown but if so that's not what the comment says.

  2. +++ b/core/lib/Drupal/Component/Annotation/Doctrine/DocParser.php
    @@ -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);
    

    Makes sense to mimic Doctrine here.

  3. +++ b/core/modules/rdf/src/Entity/RdfMapping.php
    @@ -148,7 +148,9 @@ public function calculateDependencies() {
       }
    diff --git a/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    
    diff --git a/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    new file mode 100644
    
    new file mode 100644
    index 0000000000..2c2aa7893e
    
    index 0000000000..2c2aa7893e
    --- /dev/null
    
    --- /dev/null
    +++ b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    
    +++ b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    +++ b/core/modules/rdf/tests/src/Traits/EasyRdf_ParsedUri.php
    @@ -0,0 +1,352 @@
    
    @@ -0,0 +1,352 @@
    +<?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.
    

    Oof but it's probably better than relying on a dev version.

alexpott’s picture

@catch thanks for the review. I've tried to improve the comment to reflect what happens when system.site is not present.

Re #208.3 the reason I think this fix more desirable than using the dev-master tag is that there are API changes there - that's why earlier patches that were installing the dev-master were doing:

+++ b/core/modules/rdf/rdf.module
@@ -10,6 +10,16 @@
+if (class_exists('\EasyRdf\Parser\Rdfa')) {
+  class_alias('\EasyRdf\Parser\Rdfa', '\EasyRdf_Parser_Rdfa');
+  class_alias('\EasyRdf\Graph', '\EasyRdf_Graph');
+  class_alias('\EasyRdf\Resource', '\EasyRdf_Resource');
+}

Do the class alias means that runtime code in D8 cxontrib modules will continue to work as it does now. Yes it might trigger a deprecation in PHP 7.4 but it'll still work.

mondrake’s picture

FWIW, I run a test on TravisCI with PHP 7.4 and with patch in #205 on an experimental db driver:

https://travis-ci.org/mondrake/drudbal/builds/645983785?utm_medium=notif...

All green.

Incidentally, job #14 there runs some test groups on the core SQLite driver, also all good.

catch’s picture

Version: 9.0.x-dev » 8.9.x-dev
Status: Reviewed & tested by the community » Needs work

Committed 534ee0d and pushed to 9.0.x. Thanks!

Leaving open for the 8.9.x/8.8.x backport.

If there are clean-ups for the 9.0.x commit let's try to spin them off to follow-up issues.

  • catch committed 534ee0d on 9.0.x
    Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi....
alexpott’s picture

For 8.8.x we have the following conflicts...

error: core/modules/rdf/tests/src/Traits/RdfParsingTrait.php: does not exist in index
error: core/tests/Drupal/KernelTests/Core/Test/Comparator/MarkupInterfaceComparatorTest.php: does not exist in index

So we need #3090017: Isolate test dependency on easyrdf/easyrdf to a single trait to land in 8.8.x before continuing to work on that branch... but we're good to go on 8.9.x so reviews of #213 would be great.

mondrake’s picture

#213 adjusts the fix for CompiledRoute to legacy D8-supported Symfony 3, and reintroduces the fix for LinkItem that was already in patches up to #175, and dropped in later patches since that entire legacy part is removed in D9.

The patch runs OK on all platforms down to lowest supported PHP 7.0.

So, good to go for D.8.9, I think.

catch’s picture

Version: 8.9.x-dev » 8.8.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed e6f084b and pushed to 8.9.x.

Moving to 8.8.x and 'to be ported' for after the easyrdf patch is in.

  • catch committed e6f084b on 8.9.x
    Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi....
alexpott’s picture

mondrake’s picture

So this completes the journey.

Maybe the release notes need amendment to notify module developers that if they need to rely on easyrdf in PHP 7.4 without the rdf module, they need to alias the forked class by themselves (at least until easyrdf publish a new point release - which itself would not be a simple change given the namespace change that that would bring).

  • catch committed 7330f73 on 8.8.x
    Issue #3086374 by mondrake, alexpott, joseph.olstad, Spokje, ravi....
catch’s picture

Status: Reviewed & tested by the community » Fixed

@mondrake that shouldn't go in a release note which is more for site admins, there's no runtime implication for that easyrdf change and it won't make existing sites wors. It could go in a change record maybe?

Committed 7330f73 and pushed to 8.8.x. Thanks!

alexpott’s picture

Also if you doing have runtime code that is using easyrdf and running on PHP 7.4 - you don't actaully need to update - yes it will generate deprecation notices but that's all - and depending on how you have error reporting configured you might not even log them let alone see them.

Mile23’s picture

Just a heads up... This change might be responsible for failing local tests when running phpunit instead of run-tests.sh, discovered by @Beakerboy: https://drupal.slack.com/archives/C223PR743/p1581196846035900?thread_ts=...

OK, this is interesting. ./vendor/bin/phpunit -c core/ --testsuite unit --group Annotation runs the tests and some of them fail. php ./core/scripts/run-tests.sh --dburl mysql://root:root@localhost:8889/d8 --sqlite foo.sqlite --concurrency 5 --types PHPUnit-Unit Annotation tells me to update my PHPUnit with composer run-script drupal-phpunit-upgrade and so I do. And then when I run it again, the tests pass.

alexpott’s picture

@Mile23 this is not responsible for that beyond making Drupal compatible with PHP 7.4. This happens because of PHP deprecations triggered by PHPUnit. And sure if you upgrade PHPUnit you're not going to trigger those deprecations. Not much we can do about that here.

Liam Morland’s picture

People interested in system requirements may be interested in #3114079: Update minimum supported Apache version to >= 2.4.7.

nils.destoop’s picture

In case someone is searching for the 8.8.2 patch.

alex.skrypnyk’s picture

Could someone please clarify if there is an intent to backport this to `8.7.x` branch. The security support for `8.7.x` is until June 3, 2020. Thanks

Berdir’s picture

As you said yourself, 8.7 is in _security support_, that means the only changes that are backported are security fixes, this does not include PHP 7.4 compatibility.

fabienly’s picture

Hello for information,

I tried to applied patch via composer on core 8.8.3 and php 7.4 and it doesn't applied.
I am using postgreSQL database

$psql -V
psql (PostgreSQL) 9.2.24

The serveur is Centos 7

$cat /etc/centos-release
CentOS Linux release 7.7.1908 (Core)

error log :

$composer update
  - Removing drupal/core (8.8.3)
Gathering patches for root package.
Removing package drupal/core so that it can be re-installed and re-patched.
Loading composer repositories with package information
Deleting web/core - deleted
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
Gathering patches for root package.
Gathering patches for dependencies. This might take a minute.
  - Installing drupal/core (8.8.3): Loading from cache
  - Applying patches for drupal/core
    https://www.drupal.org/files/issues/2020-02-06/3086374-8.8.x-218_0.patch (Make Drupal 8 & 9 compatible with PHP 7.4)
   Could not apply patch! Skipping. The error was: Cannot apply patch https://www.drupal.org/files/issues/2020-02-06/3086374-8.8.x-218_0.patch

This is my drush status :

$drush status
 Drupal version   : 8.8.3
 Site URI         : http://default
 DB driver        : pgsql
 DB hostname      : localhost
 DB port          : 5432
 DB username      : bnppre
 DB name          : bnppre_db
 Database         : Connected
 Drupal bootstrap : Successful
 Default theme    : bartik
 Admin theme      : seven
 PHP binary       : /usr/bin/php
 PHP config       : /etc/php.ini
 PHP OS           : Linux
 Drush script     : /home/real-estate/vendor/drush/drush/drush
 Drush version    : 10.2.2
 Drush temp       : /tmp
 Drush configs    : /home/real-estate/vendor/drush/drush/drush.yml
 Install profile  : standard
 Drupal root      : /home/real-estate/web
 Site path        : sites/default
 Files, Public    : sites/default/files/public
 Files, Temp      : /tmp
jacob.embree’s picture

You don't need to apply this patch to Drupal 8.8.3 because it was included in that release already.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Eugene Bocharov’s picture

Is it me or we also should make change in /core/lib/Drupal/Core/Render/Element.php
from:

  public static function property($key) {
    return $key[0] == '#';
  }

to:

  public static function property($key) {
    return isset($key[0]) && $key[0] == '#';
  }

Like it's be done at child() method. Since $key may be integer here too.

I'm not sure, should I comment here or open new issue, and make patch for 8.8.x-dev, 8.9.x-dev or 9.1.x-dev.

fgm’s picture

Or for Drupal 9, could use:

public static function property($key) {
    return ($key[0] ?? '') === '#';
}