Problem/Motivation

\Drupal\Component\Utility\Unicode::truncate() allows passing NULL as string to truncate - the cause of deprecation on PHP 8.1.

- https://git.drupalcode.org/project/drupal/-/commit/228a402dbd570b16aa447...
- https://git.drupalcode.org/project/drupal/-/commit/1167b6ebff2226345e45a...

Steps to reproduce

Run on PHP 8.1
- \Drupal\Tests\link\Functional\LinkFieldTest::testLinkSeparateFormatter()
- core/modules/menu_link_content/tests/src/Kernel/Plugin/migrate/source/MenuLinkTest.php

  16x: strtolower(): Passing null to parameter #1 ($string) of type string is deprecated
    16x in LinkFieldTest::testLinkSeparateFormatter from Drupal\Tests\link\Functional

  5x: mb_strlen(): Passing null to parameter #1 ($string) of type string is deprecated
    5x in LinkFieldTest::testLinkSeparateFormatter from Drupal\Tests\link\Functional


  6x: mb_strlen(): Passing null to parameter #1 ($string) of type string is deprecated
    6x in MenuLinkTest::testSource from Drupal\Tests\menu_link_content\Kernel\Plugin\migrate\source

Proposed resolution

Fix code to not pass NULL.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

andypost created an issue. See original summary.

andypost’s picture

other option will be to fix \Drupal\Component\Utility\Unicode::truncate() but I think it will hide error (better to make the interface stricter)

andypost’s picture

StatusFileSize
new663 bytes

Let's see what will fail

andypost’s picture

StatusFileSize
new664 bytes

Wrong assertion (

andypost’s picture

andypost’s picture

Test patch #4 shows more then one failure

andypost’s picture

StatusFileSize
new745 bytes

with a fix

andypost’s picture

StatusFileSize
new1.5 KB

valid patch

The last submitted patch, 4: 3240915-4-test.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 9: 3240915-8-test.patch, failed testing. View results

andypost’s picture

12 (patch 4) vs 10 (patch 8) failures means there's other places to fix

andypost’s picture

Title: \Drupal\link\Plugin\Field\FieldFormatter\LinkSeparateFormatter::viewElements() causes deprecations on PHP 8.1 » \Drupal\Component\Utility\Unicode::truncate() causes deprecations on PHP 8.1
Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new658 bytes

I think better to fix Unicode::truncate() and could use follow-up to make interface stricter in D10

it also fixed https://git.drupalcode.org/project/drupal/-/commit/228a402dbd570b16aa447...

alexpott’s picture

Status: Needs review » Needs work

I disagree very much with #13. If we fix this in Unicode::truncate() we can't add a proper scalar typehint to it. Please revert to #2.

alexpott’s picture

Title: \Drupal\Component\Utility\Unicode::truncate() causes deprecations on PHP 8.1 » \Drupal\link\Plugin\Field\FieldFormatter\LinkSeparateFormatter::viewElements() causes deprecations on PHP 8.1
Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new933 bytes

RE-upping #2 and fixing the issue summary. If we change Unicode::truncate() then we lose the deprecation if you pass it NULL. If you pass NULL to Unicode::truncate then almost certainly your code is not behaving as you expect it to. Ie. maybe you don't have a label when you expect one.

I wrote the original fix as part #3220021: [meta] Ensure compatibility of Drupal 9 with PHP 8.1 (as it evolves)

alexpott’s picture

Title: \Drupal\link\Plugin\Field\FieldFormatter\LinkSeparateFormatter::viewElements() causes deprecations on PHP 8.1 » Passing NULL to \Drupal\Component\Utility\Unicode::truncate() causes deprecations on PHP 8.1
Issue summary: View changes
StatusFileSize
new873 bytes
new1.71 KB

We can combine the two related fixes.

alexpott’s picture

StatusFileSize
new936 bytes
new1.76 KB

This is a migration. Let's take the opportunity to do less work.

alexpott’s picture

In fact the menu link example is a case in point. If you create a menu link without a description via the UI then in the DB the description column is NULL... so if we have no description we should not be calling truncate on it and turning it into an empty string...

I created a menu link via the UI and then did the following select on the DB.

mysql> select title, link__uri, description from menu_link_content_data;
+----------------+--------------------+-------------+
| title          | link__uri          | description |
+----------------+--------------------+-------------+
| No description | http://example.com | NULL        |
+----------------+--------------------+-------------+
1 row in set (0.00 sec)
alexpott’s picture

StatusFileSize
new927 bytes
new1.78 KB

Here's the fix for #18 - let's see if any tests break.

andypost’s picture

I will check remaining tests in 4, probably more places to fix

@alexpott do you think it needs followup for assert and stricter interface?

alexpott’s picture

@andypost I think strict type hints on things like Unicode::truncate(), Html::escape() etc... are part of the scope of adding scalar typehints to core. There's no need for a specific followup here as that issue is massive and has several existing issues (I think).

alexpott’s picture

Issue tags: +Needs tests

We need to add test coverage for descriptions staying NULL during a migration.

andypost’s picture

Component: link.module » base system

Looks like yes

What do you think about assert for truncate()? I can't find similar issue

alexpott’s picture

@andypost I think we should leave that alone until we have a plan for scalar typehints. Like we might issue our deprecation so adding an assert is not necessary. Plus if you test on PHP 8.1 you get that for free right now :)

daffie’s picture

Status: Needs review » Needs work

Back to needs work for the needed tests.

andypost’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new872 bytes
new2.63 KB

Probably kind of it should work but other overriding \Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase::testSource() method in testing class for checking existence of "destination" field in second row could also work

alexpott’s picture

@andypost we need an assertion somewhere that description is NULL (and not an empty string). FWIW the change in #28 doesn't fail on HEAD.

alexpott’s picture

StatusFileSize
new1.78 KB

I've step debugged through the code and realised that the change here does not need a test. I incorrectly assumed that Unicode:truncate(NULL) would return an empty string. It does not it returns a NULL (and on PHP 8.1 it'll issue a deprecation as this occurs because we pass NULL into mb_strlen()). Therefore, even on HEAD description is set to NULL if options/attributes/title is not set. So the patch in #19 is good to go here. Re-uploading. The test change in #28 passes on HEAD so it's not really telling us anything new.

andypost’s picture

Status: Needs review » Reviewed & tested by the community

That's where I stuck, thank you

  • catch committed caf0971 on 9.3.x
    Issue #3240915 by andypost, alexpott: Passing NULL to \Drupal\Component\...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed caf0971 and pushed to 9.3.x. Thanks!

Status: Fixed » Closed (fixed)

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