Problem/Motivation
The service decorator Drupal\ui_patterns\ComponentPluginManager is incorrectly implemented.
It extends Drupal\Core\Theme\ComponentPluginManager and calls parent:: methods instead of using the decorated service.
This bypasses Drupal’s service decoration mechanism, so additional decorators or alternative implementations of component_plugin_manager are ignored.
Expected Behavior
The ComponentPluginManager in ui_patterns should call the decorated service, not the parent class.
// Wrong (current implementation):
parent::processDefinition($definition, $plugin_id);
// Correct (expected behavior):
$this->decorated->processDefinition($definition, $plugin_id);
Proposed Resolution
- Inject the decorated
component_plugin_managerservice via the constructor. - Replace all
parent::calls with calls to$this->decorated.
<?php
use Drupal\Core\Theme\ComponentPluginManagerInterface;
class ComponentPluginManager implements ComponentPluginManagerInterface {
protected ComponentPluginManagerInterface $decorated;
public function __construct(ComponentPluginManagerInterface $decorated) {
$this->decorated = $decorated;
}
public function processDefinition(&$definition, $plugin_id) {
// Delegate to the decorated service.
$this->decorated->processDefinition($definition, $plugin_id);
// Add ui_patterns-specific logic here if needed.
}
// Delegate other methods likewise...
}
Impact
- Breaks Drupal’s service decoration mechanism.
- Prevents other modules from properly decorating
component_plugin_manager. - Reduces extensibility and violates expected Drupal service design.
Summary
Drupal\ui_patterns\ComponentPluginManager should delegate to the decorated service, not the parent class, to correctly follow Drupal’s service decoration pattern and maintain extensibility.
Issue fork ui_patterns-3551586
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
pdureau commentedComment #4
christian.wiedemann commentedComment #5
christian.wiedemann commentedThe decoration stuff was not straight forward as a thought. Drupal Core doesn't resolve references well for that reason loading our components fails because the validation is done before the reference loading is done. So we need to ensure that our service is the first one loads the components and cache them to the decorated service. This works well with Canvas because Canvas added it logic to setCachedDefinitions.
Comment #6
pdureau commentedIt will be fixed in this Core issue: #3352063: Allow schema references in Single Directory Component prop schemas
Comment #7
pdureau commentedFor information, related issue on Canvas side: #3552818: Contrib compatibility: ComponentPluginManager decorator should call decorated service instead of parent
Comment #8
pdureau commentedLet's wait to see what Canvas is doing.
Comment #9
grimreaperComment #10
grimreaperComment #11
grimreaperMR created on Canvas side too :)
Comment #12
grimreaperComment #13
wim leersThanks so much for getting this going, @grimreaper! Especially for your Canvas MR.
However, this particular service is extraordinarily tricky to correctly decorate. See https://git.drupalcode.org/project/canvas/-/merge_requests/961/diffs?com... for the changes I pushed — would appreciate your confirmation over there 🙏
And if I'm right there, then this MR will also need adjusting.
Comment #14
grimreaperYes.
Updating this MR regarding your latest changes on Canvas' side.
Comment #15
grimreaperFinally, not a lot of changes.
I have the remaining failing test green on my local environment...
If someone wants to test.
I have tested both UIP2 and Canvas enabled on the same site.
Comment #16
just_like_good_vibesi have tested on my local environment, and the tests are red too.
i have a fix, i will push it in the MR if you don't mind.
i want to pinpoint a potential issue about the cacheBackend.
don't we need distinct cache keys from the decorated service?
our cached definitions contain ui_patterns annotations that the decorated service may not read back as its own under 'component_plugins' cache entries.
also, the decorated service's cache backend may be already configured by its own constructor.
what about this ?
Comment #18
grimreaperRegarding comment 16 I don't know if it is needed but I don't think it can harm current behavior, so ok if you want to add it.
Comment #19
just_like_good_vibesi did a new mr, green and everything works fine. i also did a battery l tests with and without canvas installed.
seems ok for merge. you give it a try?
Comment #20
grimreaperThanks.
I gave it a try with Canvas and it was ok for me too.
I am ok to merge.
And if it will need an adjustment after Canvas' issue is merged, let's do that in a follow-up.
Comment #21
just_like_good_vibesok let's go :)
Comment #22
just_like_good_vibesComment #24
just_like_good_vibesComment #26
dalemoore commentedWould this issue be the reason why, when I've been using UI Patterns on my site fine for a while, and then install Canvas, none of my components show up in Canvas? If I add the components to separate site that doesn't use UI Patterns, they all load fine in the Canvas UI. I also, when running ddev drush cr, get complaints about prop shapes.
Comment #27
pdureau commentedHi Dale,
there are actually 2 incompatibilities between UI Patterns and Canvas, and both needs to be fixed in both sides:
Comment #28
dalemoore commentedOkay thanks Pierre, will investigate in the morning!