Problem/Motivation
Config schema provides several different means for dynamic schemas. However, they do not work for the type
of a top-level item.
For example, Page Manager reuses block plugins.
It needs to designate part of it's config schema as reusing the block plugin config schema.
page_manager.block_plugin.*:
type: block.settings.[id]
Proposed resolution
Reuse the "expand type to account for dynamic portions" code to also run for the top-level type.
This is accomplished by splitting \Drupal\Core\Config\TypedConfigManager::getDefinition() into two standalone methods, and using them at all levels to process the type.
Remaining tasks
N/A
User interface changes
N/A
API changes
N/A, thanks @vasi for figuring out a BC-safe way to do this!
Comment | File | Size | Author |
---|---|---|---|
#45 | interdiff.txt | 2.84 KB | tim.plunkett |
#45 | 2392057-config-schema-45.patch | 7.84 KB | tim.plunkett |
#42 | interdiff.txt | 1.98 KB | tim.plunkett |
#42 | 2392057-config-schema-41.patch | 7.84 KB | tim.plunkett |
#39 | interdiff.txt | 593 bytes | vasi |
Comments
Comment #1
tim.plunkettThis should fail.
Comment #2
tim.plunkettIf you change this line to refer to the plugin directly, test.plugin_types.wrapper, then the test passes.
Comment #4
mahtoranjeet CreditAttribution: mahtoranjeet as a volunteer and commentedComment #5
mahtoranjeet CreditAttribution: mahtoranjeet as a volunteer and commentedComment #6
benjy CreditAttribution: benjy at PreviousNext commentedI've re-rolled this with the failing patch, attached.
I started debugging this in TypedConfigManager::buildDataDefinition() and i'm not sure if it's correct but what i'm seeing is that:
Inside getDefinition, $type gets turned back into
wrapping.test.plugin_types.*
which then does agetDefinition('test.plugin_types.[plugin_id]')
which does not pick uptest.plugin_types.wrapper
definition and therefore internal_value does not get it's schema.Comment #9
benjy CreditAttribution: benjy at PreviousNext commentedOK, this patch fixes the issue. I'm not sure it's exactly right but I wanted to see what else might fail.
Comment #10
Gábor HojtsyWhere is the plugin_id key defined (with its type)?
Comment #11
benjy CreditAttribution: benjy at PreviousNext commentedI think it's just missing from this test example? test.plugin_types.* would provide the definition for that?
Comment #12
Gábor HojtsyAll right, its just in the dynamic type but it is defined in the base type. Makes sense.
Comment #14
tim.plunkettThis blocks CTools.
The sub_type processing didn't calculate fallbacks properly.
Comment #15
Gábor HojtsyI think the patch looks generally good, it would be nice to outline the solution in the summary, so committers have an understanding. Two notes though:
Would be good to add a short summary comment on why the prior call is different.
So you just added this new value argument or is that already on the interface?
Comment #16
dsnopekJust a note: this issue is now blocking Panels and Panelizer as well, and the patch from #14 allows everything to work for me!
Comment #17
benjy CreditAttribution: benjy at PreviousNext commentedI added the new parameter, when we're handing sub-types we need to pass the parent definition along to getDefinition() which is why they're different from the calling code. This does raise a good point, anyone using TypedConfigManager needs to be aware that without passing $value along to getDefinition(), sub-types won't be expanded correctly, in addition, we should update the interface docs.
Comment #18
Gábor HojtsyAll right, if the public interface needs to change, that may not be allowed before Drupal 9. How does PHP react if an optional argument is added on an interface but not yet added in an implementation? Does that count as a fatal for not implementing the interface properly or not? http://php.net/manual/en/language.oop5.interfaces.php does not seem to document that, maybe this comment is relevant: http://php.net/manual/en/language.oop5.interfaces.php#77950 -- that would suggest we cannot add a new optional argument on an interface and assume that will not break BC?
Comment #19
benjy CreditAttribution: benjy at PreviousNext commentedYeah that would be a fatal, we could probably write this in a different way to avoid backward compatibility. We'd need an internal method that did something like what getDefinition() does now which can be used correctly by buildDataDefinition() and then we'd keep getDefinition() as is, and add a new method like, getComplexDefinition()?
Although, that's all just a workaround, the right thing is to add the new parameter as it is required for getDefinition() to correctly calculate the definition, unless we can solve that another way? I don't think it's possible to derive it.
Comment #20
alexpottWe need to update the documentation on
TypedConfigManagerInterface::getDefinition()
... I'm not wild about adding a parameter to that method considering it comes from\Drupal\Component\Plugin\Discovery\DiscoveryInterface
If we proceed with the patch as is we're going to have to make a tough choice about was this means for BC. I'm not sure this is acceptable in a patch release.
Comment #21
alexpottWhat happens if we get another bracket?
Comment #22
tim.plunkettI need to revisit this. Running
protected $strictConfigSchema = FALSE;
in all my tests is unfortunate.Comment #23
tim.plunkett@alexpott, do you mean
type: test.[foo].[bar]
? Yowch.Comment #24
tim.plunkettAgreed about the patch release, unless we come up with something clever/safer
Comment #25
vasi CreditAttribution: vasi at Evolving Web commentedI don't think we actually have to change the interface, we're only using the extra parameter internally. We can just pull out the logic of getDefinition() into an internal helper method, and then keep the interface the same.
Comment #26
benjy CreditAttribution: benjy at PreviousNext commentedYou may be interested in #2580389: Allow test classes to specify the config object exceptions - that lets you exclude individual objects from the validation.
Comment #27
tim.plunkett#26 Yeah I know that part, it's just that the parts that aren't validating are dynamic and unpredictable. Hence this issue :)
#25 is simple yet brilliant. Thanks so much @vasi!
Still unsure about #21.
This streamlines the new method a bit.
Comment #28
tim.plunkettOkay, added test coverage for double brackets. It Just Works™, thankfully.
Comment #30
tim.plunkettComment #31
YesCT CreditAttribution: YesCT commentedwhat is this for?
this might be a bit more clear if we dont use "foo" to mean two different possible things.
missing type
could be better english grammar.
merge? maybe a better var name, or inline.
Comment #32
tim.plunkettThanks @YesCT!
Comment #33
tim.plunkettWhoops, missed the feedback from #31.1
Changing #31.2 to be less confusing by not duplicating 'foo'
Also I streamlined the initial call to getDefinitionWithReplacements by skipping the else, and using an array typehint.
Since I changed the logic AND the test slightly, redoing the PASS/FAIL thing.
Comment #34
YesCT CreditAttribution: YesCT commentedthanks for the issue summary update, and the conversation while we discussed this, latest patch addresses the feedback I had and alex's, thanks!
Comment #36
tim.plunkettOkay that variable name and its optionalness was bothering me. Just a nit, so not changing status back.
Also, please check the credit box for @YesCT, she was instrumental in helping me push this forward, in addition to her thorough reviews
Comment #37
alexpottThis approach looks great - nice work.
Same description for two different tests - which is a bit confusing. Perhaps we can improve the test documentation to show what schemas are being used where - so reviewers have to think less :)
Comment #38
alexpottAdded credit ticking for reviewers.
Comment #39
vasi CreditAttribution: vasi at Evolving Web commentedChanged the description for the second test, I hope that's descriptive enough.
Comment #40
tim.plunkettI think @vasi's change is sufficient.
As far as the follow-up, we do still "use" the $exception_on_invalid, it defaults to TRUE, and before we didn't specify it:
Comment #41
alexpottSo how will this code throw or not an exception based on this boolean?
Comment #42
tim.plunkettAs @alexpott pointed out in IRC, since getDefinition() never calls parent::, the $exception_on_invalid handling in
\Drupal\Component\Plugin\Discovery\DiscoveryTrait::doGetDefinition()
never runs.So let's pass around this pointless parameter to maintain the previous behavior, but document its pointlessness.
Comment #43
alexpottCommitted 9ccbfda and pushed to 8.1.x. Thanks!
To commit this bug fix to 8.0.x we need to prefix these methods with an underscore.
Comment #45
tim.plunkettThanks! Added the underscores.
Comment #46
tim.plunkettRe-RTBC-ing now that it passed with underscores.
Comment #47
alexpottThanks Tim.
Committed 4335d12 and pushed to 8.0.x. Thanks!
Comment #49
Gábor HojtsyYay, thanks all! Great seeing important bugs fixed with config schema :) All of contrib will be happy :)
Comment #50
benjy CreditAttribution: benjy at PreviousNext commentedCould be related to this: #2661710: Problems with page_manager.page_variant.* schema
Comment #51
alexpottThis introduced some problems... #2663410: TypedConfigManager::_getDefinitionWithReplacements() incorrectly replaces generic definition
Comment #52
Berdir(Edit: crossposted with alex)
Found a nasty bug with this: #2663410: TypedConfigManager::_getDefinitionWithReplacements() incorrectly replaces generic definition.
Page Manager only works because we don't have any tests that are adding more than one block of different types to the same display variant.
See also #2663376: The core block_settings schema defines schema for block_content blocks for another confusing thing that is partially hiding this the problem here.