Problem/Motivation
#3064854: Allow Twig templates to use front matter for metadata support introduced the ability for templates to provide metadata using front matter.
This can potentially allow plugin managers that associate plugin definitions with templates (examples: layouts, help_topics) to inline the plugin definition with the template itself. Otherwise, you would need to put definitions into separate files and discover them using YamlDiscovery.
Proposed resolution
Introduce a new TemplateDiscovery abstract class that can be extended to discover plugins from Twig templates.
Use the template filename as the plugin ID, and allow extending classes to define what to do with extracted FrontMatter metadata.
Remaining tasks
- [Done] Create patch containing a new abstract class for Twig template-based plugin discovery.
- [Done] Create a sample usage. Usage by Help Topics is on #3176735: Replace Drupal\help_topics\HelpTopicDiscovery with core/lib Twig discovery class; RTBC when this issue is finalized.
- [Done] Create unit tests. These can be based on the unit tests for the existing help topics discovery class.
- [Done] Review the patch with the new class and unit test.
- Commit
User interface changes
None
API changes
New API will be introduced; no changes to existing APIs.
Data model changes
None
Release notes snippet
A new plugin discovery method has been added that discovers plugins in Twig templates. See https://www.drupal.org/node/3212845 for more information.
| Comment | File | Size | Author |
|---|---|---|---|
| #53 | 3075427-53-with-usage.patch | 14.74 KB | andypost |
| #53 | 3075427-53.patch | 9.8 KB | andypost |
Comments
Comment #2
markhalliwellThis is currently blocked.
Comment #5
lauriii#3064854: Allow Twig templates to use front matter for metadata support was committed.
Comment #6
jhodgdonThis should be an easy patch to make. We have the class and tests already in the experimental Help Topics module in core.
See
core/modules/help_topics/src/HelpTopicDiscovery.php (note that it uses the Help Topics FrontMatter class and not the one that is now in core/lib/Drupal/Component/FrontMatter/FrontMatter.php , so that will need an update)
and
core/modules/help_topics/tests/src/unit/HelpTopicDiscoveryTest.php
So basically, the names of these classes need to be changed, and they need to be moved out of the help_topics module into the core/lib namespace, to the same locations as classes/tests for other types of plugin discovery.
Comment #7
andypostAt the moment we can't replace
core/modules/help_topics/src/HelpTopicDiscovery.phpbecause it has TODO (with outdated link)But it's totally fine to move it to component and inherit help_topics from it (to limit discovery by help_topics module)
The only question is namespace for new service (and test)
Comment #8
jhodgdonGood point. So the classes we would create would be *mostly* like the ones currently in Help Topics that I listed in #6. :)
Comment #9
andypostMaybe @markcarver can elaborate because this issue is a blocker for #3075432: Inline .layouts.yml definitions with each template
As I recall core won't accept changes that is not used but we can't use it for help topics as it's not stable yet
Comment #10
jhodgdonThis was marked as un-postponed by a Drupal Core maintainer, so I think it is OK to proceed.
Comment #12
jhodgdonI started looking at this, but I realized quickly that we have additional help-topic-specific code in our Discovery class, besides what is in #7:
a) When we discover a help topic twig template, we assign it a plugin class of HelpTopicTwig.
b) When we parse out the front matter meta-data, we look for 'label', 'top_level', and 'related', and we fail if there is anything else.
So... I'm not sure how useful it will really be to do this. We could make some kind of an abstract class with some kind of a validateAndSaveFrontMatter() abstract method I guess? But it's not as simple as just copying the classes we have.
Comment #13
jhodgdonCould be something like this?
Comment #14
jhodgdonAs another note, the other plugin discovery classes are all in Drupal\Core but are small wrappers around Drupal\Component classes. I didn't do that here, but probably we should.
Comment #15
andypostSetting NW as there's great starting patch! Thank you @jhodgdon
it could use PHP's type hints now to string for last 2 arguments
expected keys could use docs
each provider could have own pattern to filter files
Comment #16
jhodgdonI'm working on this. I plan to make a patch that uses it to replace the custom discovery in Help Topics as a proof of concept, as well as cleaning this up.
Comment #17
jhodgdonHere's (I think) a viable patch.
I've attached:
- An interdiff for the generic discovery class as compared to the non-working earlier patch.
- A patch containing just the generic discovery class. This one doesn't really do anything, just adds the class file. Question: should this have both a Core and Component class, as there are in the other Discovery classes? I'm not really sure. Also it probably needs some kind of a test.
- A patch containing that class and the Help Topics module using it. The help topics portion should go onto #3176735: Replace Drupal\help_topics\HelpTopicDiscovery with core/lib Twig discovery class if this issue gets done.
I didn't run all of the help topic classes, but the HelpTopicTest function test does pass locally. Let's see what happens.
Comment #18
andypostQuickly skimmed, looks great and explains the idea!
Comment #19
jhodgdonCode sniff found several unused use statements. Removing from both patches. Interdiff is from the larger "with usage" patch to the new "with usage" patch.
Comment #21
jhodgdonOne small adjustment to a test is needed in the "with usage" patch, because the exception message is more generic in this patch.
So here's a new "with usage" patch. No changes to the patch in #17 without usage.
Comment #23
jhodgdonHere's a new patch. I've added some additional docs to the class on how to use it. I did not update the "usage" patch, as this only added docs. This patch still needs tests. Also updated the issue summary on what needs to be done.
Comment #24
andypostLooks ready to be used for templates and tests
Comment #25
jhodgdonYes, I think it's ready. I plan to make tests for the patch later today (adapt the tests we wrote for the Help Topics specific template discovery).
And based on the "with usage" patch, if this is committed we are ready to use it as-is in Help Topics. The latest "with usage" patch has the exact same class (minus the new docs added in comment #23, which are based on how we can use it in Help Topics, slightly simplified).
Comment #26
jhodgdonAnd here is the same patch with a test class added. I made no changes to the TemplateDiscovery class, so the interdiff is the added test class.
Something weird is happening on my local system lately when I run unit tests (they hang), so I am not certain whether the test passes or fails. I think it might fail but it should be close.
Comment #27
jhodgdonI have a patch that fixes the one-line code sniff problem but I cannot seem to upload it (getting 5xx server errors).
Comment #28
andypostHere's it
Comment #30
jhodgdonHere's a fix for the test, if I can upload a patch now...
Comment #32
jhodgdonAnd one more test fix.
Comment #33
jhodgdonThere we go -- green! I think this patch is ready to go. @andypost, I think you're eligible to review it if you want, since your making-patch contributions so far were one blank line added. :)
Comment #34
andypostI find it mostly ready, great job!
Could be interesting to try use it for #3075432: Inline .layouts.yml definitions with each template
I bet $rootProvider is better wording
Both needs to add `: array` to point that functions return array
Not clear why cast to array applied
The comment could be moved one line down
Comment #35
jhodgdonGreat points, thanks!
On item #3, the constructor is documented thus:
(and similar for $this->directories). So, you don't know if it's a string or an array, and you need to cast to array.
Here's a patch/interdiff fixing the other items from #35.
Comment #36
andypostThank you, about #3 is clear
Comment #37
jhodgdonSmall summary update to say related issue patch has been created/moved. Also created a change notice.
https://www.drupal.org/node/3212845
Comment #39
andypostTest bot flux
Comment #41
jhodgdonLooks like a random fail in Drupal\Tests\layout_builder\FunctionalJavascript\LayoutBuilderDisableInteractionsTest
Comment #42
tim.plunkettAssigning myself to review
Comment #43
tim.plunkettAs this is being proposed to replace or augment YAML discovery (at least for layouts), it'd be good to have an equivalent method to
\Drupal\Core\Plugin\Discovery\YamlDiscovery::addTranslatableProperty(), which LayoutPluginManager calls 3x for label, description, and category.This example is confusing because it doesn't mention TemplateDiscovery at all (also the code wrapping is needlessly confusing).
I think this patch should include a TemplateDiscoveryDecorator to make adding it to existing plugins easier. See YamlDiscoveryDecorator for an example.
Oh now the first comment makes a little more sense. It's not 100% clear to me why it's done this way, requiring an entire new class, instead of letting the plugin manager's
processDefinition()handle it (and handling the translatable needs as mentioned above)It's not 100% clear why this is restricted to Twig. (I don't know what else we would use it for, just curious)
This method is not backed by any interface and is not called anywhere else, it should be protected/private
Nit: I don't think the trailing comma is needed.
This is a rather complex conditional. Also it uses !== in one place and != in another.
It may seem like overkill, but can the major parts of the conditional be first assigned to helpfully named variables?
Odd for a "Save" method to return data. Would that be better named Process or Parse?
"throw an exception IF there is an error"
Also what type should the exception be? We should decide and then this method should have an @throws (potentially instead of this comment)
Comment #44
cyb_tachyon commentedNoting that there is a contrib module implementation of parts of this feature here: https://drupal.org/project/patternkit
It may have some helpful programming patterns and design decisions for this patch if jhodgdon and tim.plunkett could take a look.
I will have some time in November, but not before then and I don't want to delay this functionality.
Comment #45
finnsky commentedHello all! Created patch based on previous #35 and comments from #44
So FrontMatterDiscovery.
https://jekyllrb.com/docs/front-matter/#custom-variables
what can be very useful in components driven development with storybook or similar.
So plugins should be defined in `plugins` section of yaml frontmatter.
But this is optional in this patch and can be controlled with $array_position variable
Comment #46
finnsky commentedComment #47
ankithashettyTried to fix the custom command failure errors in both the patches provided in #45 and attaching an interdiff as well for reference.
Thanks!
Comment #49
amber himes matzThe last patches failed with "PHP 8.0 & MySQL 5.7 Custom Commands Failed" but the status wasn't changed automatically to "Needs work", so changing status now. Also, these patches should now be tested/updated/reviewed on 9.4.x. Thank you.
Comment #52
andypostfix cspell and combined example patch
Comment #53
andypostfix phpstan and needs to add tests from #35
Comment #56
andypostComment #57
kristen polThis one has gone cold. Are people still interested in getting this in?
Comment #58
andypostIt needs subsystem manager review as it used by help module only
Comment #59
amber himes matz@andypost -- Are you looking for a high-level overview of the approach in #53 from a Theme API subsystem maintainer before continuing work on it? Do you want me to ping maintainers in Slack to take a look, or do you want to make any updates to the patch first?