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
Comment #2
andypostpatch from https://git.drupalcode.org/project/drupal/-/commit/1167b6ebff2226345e45a...
Comment #3
andypostother option will be to fix
\Drupal\Component\Utility\Unicode::truncate()but I think it will hide error (better to make the interface stricter)Comment #4
andypostLet's see what will fail
Comment #5
andypostWrong assertion (
Comment #6
andypostComment #7
andypostTest patch #4 shows more then one failure
Comment #8
andypostwith a fix
Comment #9
andypostvalid patch
Comment #12
andypost12 (patch 4) vs 10 (patch 8) failures means there's other places to fix
Comment #13
andypostI think better to fix
Unicode::truncate()and could use follow-up to make interface stricter in D10it also fixed https://git.drupalcode.org/project/drupal/-/commit/228a402dbd570b16aa447...
Comment #14
alexpottI 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.
Comment #15
alexpottRE-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)
Comment #16
alexpottWe can combine the two related fixes.
Comment #17
alexpottThis is a migration. Let's take the opportunity to do less work.
Comment #18
alexpottIn 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.
Comment #19
alexpottHere's the fix for #18 - let's see if any tests break.
Comment #20
andypostI will check remaining tests in 4, probably more places to fix
@alexpott do you think it needs followup for assert and stricter interface?
Comment #21
alexpott@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).
Comment #22
alexpottWe need to add test coverage for descriptions staying NULL during a migration.
Comment #23
andypostLooks like yes
What do you think about assert for truncate()? I can't find similar issue
Comment #24
alexpott@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 :)
Comment #25
andypost-deleted-
Comment #26
andypostSorry, mixed comment forms with #3241296-5: core/tests/Drupal/KernelTests/Core/Path/PathValidatorTest.php triggers deprecations on PHP 8.1
Comment #27
daffie commentedBack to needs work for the needed tests.
Comment #28
andypostProbably 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 workComment #29
alexpott@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.
Comment #30
alexpottI'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.Comment #31
andypostThat's where I stuck, thank you
Comment #33
catchCommitted caf0971 and pushed to 9.3.x. Thanks!