Problem/Motivation

\Drupal\Core\Plugin\DefaultPluginManager::findDefinitions() checks for a 'provider' key in the plugin definition array, and removes the definition if the provider does not exist.

However not all plugin definitions are arrays. It attempts to handle this by casting the object to an array, but that only works if there is a public $provider; property in the definition class, which is not ideal.

Proposed resolution

Expand \Drupal\Component\Plugin\Definition\PluginDefinitionInterface.
Previously discussed was adding a new interface, and deprecating PDI.
However, multiple issues want to expand PDI, we can't just introduce a single new interface that replaces it. We'd end up with a confusing circular dependency of which interfaces to use when and which would be deprecated.

@catch cited that problem, and https://www.drupal.org/core/d8-bc-policy, to suggest that we just expand PDI directly

Remaining tasks

User interface changes

API changes

Data model changes

Comments

tim.plunkett created an issue. See original summary.

tim.plunkett’s picture

Status: Active » Needs review
StatusFileSize
new3.27 KB
eclipsegc’s picture

Status: Needs review » Needs work

Ok, this seems pretty sane... Test coverage?

Eclipse

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new2.6 KB
new6.2 KB
new3.66 KB

Yep

tim.plunkett’s picture

StatusFileSize
new1.29 KB
new7.49 KB

Let's have EntityType get this benefit. Their provider hasn't been getting checked

The last submitted patch, 4: 2818653-provider-4-FAIL.patch, failed testing.

eclipsegc’s picture

Status: Needs review » Reviewed & tested by the community

Looks sensible and useful to me!

Eclipse

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record
+++ b/core/lib/Drupal/Component/Plugin/Definition/PluginDefinitionProviderInterface.php
@@ -0,0 +1,21 @@
+/**
+ * @todo Move to \Drupal\Component\Plugin\Definition\PluginDefinitionInterface.
+ */

This needs a 9.0.x issue and also should be more than an @todo. Also this issue should have a change record.

tim.plunkett’s picture

Also while testing this patch out on some actual code, realized we should update \Drupal\Core\Plugin\PluginDependencyTrait as well.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new7.66 KB

For #9, #2821191: Allow object-based plugin definitions to be processed in PluginDependencyTrait is now it's own issue.

#2485513: DefaultFactory cannot deal with objects as plugin definitions was the issue that added PluginDefinitionInterface. The only implementor is EntityType (and now the experimental LayoutDefinition), all other plugin definitions in core are arrays.
That issue was championed by Xano, who is responsible for the contrib Plugin module. It contains a multitude of helpers, decorators, and workarounds for core's lack of support of object-based definitions.
For example, they have their own version of PluginDefinitionInterface which already contains this method.

Because both #2821189: Allow object-based plugin definitions to be processed in DerivativeDiscoveryDecorator and this issue want to expand PDI, we can't just introduce a single new interface that replaces it. We'd end up with a confusing circular dependency of which interfaces to use when and which would be deprecated.

@catch cited that problem, and https://www.drupal.org/core/d8-bc-policy, to suggest that we just expand PDI directly.

tim.plunkett’s picture

Issue tags: +Blocks-Layouts
tstoeckler’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

This looks absolutely great.

+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -453,3 +480,49 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
+class ObjectDefinition implements PluginDefinitionInterface {

Would be nice to provide this as an actual PluginDefinition class in a non-test namespace for object-based definitions to extend. That should be a follow-up, let's get this in first.

Also added change record, so this is good to go, IMO.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update

This change looks very sensible. The one concern I have is for contrib that has implemented \Drupal\Component\Plugin\Definition\PluginDefinitionInterface. The comment in #10 allays a few of the concerns but I think the issue summary needs an update to reflect the changes made by this issue and to mkae the case for this change in 8.3.x. I'm not convinced that the plugins section on https://www.drupal.org/core/d8-bc-policy actually covers this case.

tim.plunkett’s picture

Issue tags: +blocker
tim.plunkett’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update
jibran’s picture

Status: Needs review » Reviewed & tested by the community

#13 addressed in #15 so back to RTBC.

effulgentsia’s picture

The one concern I have is for contrib that has implemented \Drupal\Component\Plugin\Definition\PluginDefinitionInterface. The comment in #10 allays a few of the concerns but I think the issue summary needs an update to reflect the changes made by this issue and to mkae the case for this change in 8.3.x. I'm not convinced that the plugins section on https://www.drupal.org/core/d8-bc-policy actually covers this case.

The plugins section doesn't, but I think that https://www.drupal.org/core/d8-bc-policy#interfaces does. From there:

When implementing the interface, module authors are encouraged to either:
Where there is a 1-1 relationship between a class and an interface, inherit from the class. Where a base class or trait is provided, use those. This way your class should inherit new methods from the class or trait when they're added.
Where the interface is implemented directly for other reasons, be prepared to add support for new methods in minor releases

I think it's a shame that we didn't add a PluginDefinitionTrait when we added PluginDefinitionInterface. But that's because we added PluginDefinitionInterface prior to the above BC policy clarification. I think it would be good though to provide that trait now, so that even though we inconvenience some contrib authors with this change, at least they'll be able to opt in to the trait and then not be inconvenienced again when we add another method in the future. I'm not necessarily opposed to punting the trait to a follow-up, but I'd feel better with committing it as part of this patch, so that the CR can instruct people about it.

effulgentsia’s picture

Would be nice to provide this as an actual PluginDefinition class in a non-test namespace for object-based definitions to extend.

That might be more sensible than a trait in this case. Since LayoutDefinition, EntityType, etc. do have a "is a" relationship to plugin definitions, so a base class is logically appropriate here, I think.

tim.plunkett’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new11.4 KB
new6.35 KB
tim.plunkett’s picture

StatusFileSize
new3.09 KB

Fixed a doc line that was because of the shift from #17 to #18.

Also, after checking on what the plugin.module provides in it's base class, adding id(). This was also already in LayoutDefinition and EntityType.
This plus #2821189: Allow object-based plugin definitions to be processed in DerivativeDiscoveryDecorator gets us to a really good place.

tim.plunkett’s picture

StatusFileSize
new12.07 KB

Ugh.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tim.plunkett’s picture

Version: 8.4.x-dev » 8.3.x-dev
Priority: Normal » Major

Still targeting this for 8.3.x
Raising to major as it is no longer just a soft blocker, but is blocking issue for the Layout Initiative, specifically for #2844302: Move Field Layout data model and API directly into \Drupal\Core\Entity\EntityDisplayBase

The last submitted patch, 19: 2818653-pdi-19.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 21: 2818653-pdi-20.patch, failed testing.

jibran’s picture

+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -298,6 +295,31 @@ protected function findDefinitions() {
+    // Attempt to convert the plugin definition to an array.
+    if (is_object($plugin_definition)) {
+      $plugin_definition = (array) $plugin_definition;
+    }

I think instead of typcasting to array either use Reflection or check for toArray and as third choice convert typecast to array.

tim.plunkett’s picture

Status: Needs work » Needs review

- if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) {

I'm not adding the cast just moving it.
No such method as toArray.
Adding reflection is out of scope.

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Fair enough!

tstoeckler’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Component/Plugin/Definition/PluginDefinitionInterface.php
@@ -12,6 +12,14 @@
   /**
+   * Gets the unique identifier of the plugin definition.
+   *
+   * @return string
+   *   The unique identifier of the plugin definition.
+   */
+  public function id();

This is confusing. Usually this is the plugin ID, the plugin definition itself does not generally have a distinct ID. The documentation needs to be updated to reflect that.

Also this should be getId(), not id(). I realize that the latter is what EntityType uses, but this is a new interface so we should be using best practice naming here, IMO.

Marking needs work for the first point at least, I realize the last point is potentially contentious.

tstoeckler’s picture

Issue tags: +#SprintWeekend2017
tstoeckler’s picture

Issue tags: -#SprintWeekend2017 +SprintWeekend2017
tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new1.33 KB
new12.23 KB

#2350807: add getId() and make id() a wrapper for it and deprecate it is for the getId() vs id() portion. This is not really in scope here, it should be a single discussion and break.

Good point on the docs! Fixed. Also removed the duplicate declaration of EntityTypeInterface::id()

tstoeckler’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, awesome that we already have dedicated issue for the getId() vs. id() thing. Docs look perfect now.

effulgentsia’s picture

Patch looks great to me. Ticking some credit boxes.

  • effulgentsia committed 701bee4 on 8.4.x
    Issue #2818653 by tim.plunkett, tstoeckler, jibran: Allow object-based...

  • effulgentsia committed 7cd2c54 on 8.3.x
    Issue #2818653 by tim.plunkett, tstoeckler, jibran: Allow object-based...
effulgentsia’s picture

Status: Reviewed & tested by the community » Fixed

Pushed to 8.4.x and cherry picked to 8.3.x. Let's update the CR to mention the id() method and base class and then publish it.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture

publish the change record