Problem/Motivation
In #3220021: [meta] Ensure compatibility of Drupal 9 with PHP 8.1 (as it evolves) the fact that EntityInterface::label() can return a NULL becomes an issue because we often pass the result of label() to string function that in PHP 8.1 trigger deprecations when not passed a string.
There are quite few places in core where the result of label() is assumed to be a string and if it is not then what happens next does not make much sense. Currently we are getting things like empty link tags, for example.
Steps to reproduce
Proposed resolution
Where the label is NULL and the result is being used in a string function for display - use the entity ID instead.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
Comment | File | Size | Author |
---|---|---|---|
#29 | 3232673-29.patch | 35.24 KB | alexpott |
#29 | 26-29-interdiff.txt | 961 bytes | alexpott |
#26 | 3232673-26.patch | 35.23 KB | alexpott |
#26 | 22-26-interdiff.txt | 3.39 KB | alexpott |
#22 | 3232673-22.patch | 33.97 KB | alexpott |
Comments
Comment #2
alexpottHere's all the label related change from #3220021: [meta] Ensure compatibility of Drupal 9 with PHP 8.1 (as it evolves). I'm not entirely sure about the scope of this and how best to do it and whether or not we want tests. Once we support PHP 8.1 we get implicit test coverage via the PHP deprecations.
This patch was generated by doing
git checkout 3220021-php81-compatibility (git diff 9.3.x 3220021-php81-compatibility -G label --name-only)
and the removing the small about of unrelated change.Comment #3
longwaveStill an @todo here. I would suggest yes, because at least the ID lets us distinguish between two entities with no label, if that ever happens.
Is this really correct? This feels out of place in test code. We should just make sure the entities under test have a label, I think.
Should we just say "Edit layout" if there is no label?
Comment #4
alexpott@longwave thanks for the review, sorry for taking a while to get back to this one.
Re #3.1 I agree that we should use the ID too... but I'm pondering if we should have a generic rule for entities that, if there is no label, then we return "content item 1" or whatever the label singular + entity ID would be. OTOH that would make more difficult to determine that a label is not set. Not sure.
Re #3.2 I think this is a good change because we're testing the unlabelled entity ID fallback :)
Re #3.3 I wonder if there possibly could be multiple layouts on the page all with Edit layout pointing to different section storages. I guess this is why I think we need something consistent to deal with an unlabelled entity.
Comment #5
alexpott@berdir pointed out the existence of #2939931: Add an implementation of EntityDisplayBase::label() which is definitely related.
Comment #6
longwaveRe #3.2 I feel that if we are testing a fallback we should have an explicit test for it, rather than using the same fallback logic in the test assertion; otherwise we risk refactoring away a test for the fallback by mistake and it becomes untested.
Comment #7
alexpott@longwave re #3.2 this is a TestBase class - and in my mind it needs to deal with whatever the Content Translation UI outputs. This patch changes that so it needs to change so support both types of label.
Here's a patch with the @todo's removed.
Comment #9
alexpottI'm really not sure that the no label behaviour in DefaultSelection is correct but it is extensively tested in \Drupal\Tests\system\Kernel\Entity\EntityReferenceSelectionReferenceableTest so I don't think we should be changing that behaviour here. It opens up quite a few cans of worms about what to do with the match operator if the label can be an entity ID.
Comment #10
alexpottI think that label is required for Contact Forms. it is in the UI... in fact this bit here is about what to do when there is no contact form - ie. it's the user contact page. So this bit looks fine. NULL is just a not default value for a string replacement value.
Let's work out why this is happening.
I don't like this change - pretty sure it is due to test roles with no labels. Let's fix that.
I don't like this change - label is required for workflows - pretty sure this is due to tests.
I've added some exceptions so we can break things to find out where the NULLs are coming from.
I still think that generic entity code has to support NULL labels as that is allowed by the interface but on entities where the label is required we should be making sure it is there.
Comment #11
longwave> I still think that generic entity code has to support NULL labels as that is allowed by the interface but on entities where the label is required we should be making sure it is there.
+1 - was looking at this patch while you posted the above comments and agree with this, in concrete cases we should figure out why the label is NULL (probably tests, as you say) but in the generic case we still need to allow it.
Comment #13
alexpottFixing the tests... leaving the exceptions in until we're green.
Comment #14
alexpottFixing the layout one too...
Comment #17
andypostMaybe it could use asserts?
Comment #18
alexpott@andypost that's a good idea. These exceptions are here just for testing and I was planning to remove them but I think once I've got this green I'll change them to asserts and add tets.
Comment #19
alexpottWe're green - changed everything to assertions. I thought about adding tests but I'm not sure it is worth it. The advantage of adding assertions is that tests will fail even on PHP versions less than 8.1.
I disagree that a change record is needed here. There is no real change here. Code like user_user_role_insert() always required a label to work as expected and in regular runtime you can't create a role without a label via the UI.
Comment #20
Berdirshould we fall back to the ID here? an empty string doesn't make sense in an option list?
most of the roles with missing label have a fixed id: admin, authenticated, test_something. should we just use the same string for the label to make it easier to identify if shown anywhere in debug output or so? clearly wasn't really needed here, but do we really need random labels?
here you did what I suggested, as it's actually used below.
Also, I thought enabled config entities do have schema validation? but I guess we have no way to make a field required there?
Comment #21
alexpottThanks for the review @Berdir
Re #20.1 I experimented with that in #7... we have extensive test coverage of this in
\Drupal\Tests\system\Kernel\Entity\EntityReferenceSelectionReferenceableTest
- I think if we want to change that we should do that in a follow-up.Re #20.2 and .3 sure we can do that. It didn't seem to matter - you've always got the ID. Part of me is tempted to change the config behaviour and if there is no label use the ID instead. But that's a much larger issue and more change. Will use the ID.
[EDIT: fixed where we have extensive test coverage... copy pasta error - thanks @Berdir]
Comment #22
alexpottLess randomness....
Comment #25
BerdirFine to leave the options thing to a separate issue if that's breaking existing tests. Is that the wrong issue though, that doesn't look related?
Yeah, test labels aren't a big deal, but IIRC you were often a proponent of _not_ using random strings when we aren't specifically testing for that too :)
Comment #26
alexpottFixing the assertions and making the docs for label() correct with the reality.
Comment #27
alexpott@Berdir checkout #7 - that patch did...
The fails are in \Drupal\Tests\system\Kernel\Entity\EntityReferenceSelectionReferenceableTest - the link in #21 was a copy paste error that I'll fix...
Comment #29
alexpottWhoops.
Comment #30
longwaveCouple of questions/comments but everything else looks OK to me now. Would be nice to get #2939931: Add an implementation of EntityDisplayBase::label() done and then we can undo some of this again, I think.
Would having a secondary sort by ID mean a more stable sort? But then all entities should really have labels and I bet this only affects tests, so it probably doesn't matter.
I guess there will never be a huge number of workspaces, but this might be asserted many times as it's inside the sort callback.
Should we just fall back to ID or '' instead here?
Comment #31
alexpottThanks for the review @longwave
RE #30.1 the problem with changing this to sort by ID when the label is missing is that this is a change in behaviour and then you are sorting the proverbial apples and pears. That's why I went for the no change to HEAD fix.
RE #30.2 well asserts should be disabled in production so the number of times is immaterial. The reason I didn't fallback to ID is the same as above - we'd then be sorting apples and pears.
I think it is best to rely on PHP 8's stable sorting for when the labels are equivalent. See https://wiki.php.net/rfc/stable_sorting - in practical terms this means the ID is used for sorting because the most common db (mysql) tends to return rows in the order of ID.
Comment #32
longwaveOK, keeping existing behaviour makes sense. Everything else looks sane so this is RTBC.
> the most common db (mysql) tends to return rows in the order of ID
PHP stable sorts will only be stable if this assumption holds, but in practice I have found making this assumption can be dangerous, especially across environments that ostensibly have the same database rows but the results of an unsorted query can be consistently returned in different orders.
Comment #33
catchSome of this starts to look a bit crufty, but I guess that's what you get with stricter typing from PHP and less strict behaviour from us, and unless we make label required to return a string we don't have other options. Making minimal changes to avoid changing current behaviour (apart from the UI message substitutions using ID as a fallback) all makes sense.
Committed 9da1866 and pushed to 9.3.x. Thanks!
Comment #35
catch