4

I have the following EntityReferenceSelection plugin:

/**
 * Provides an entity reference selection for my_entity.
 *
 * @EntityReferenceSelection(
 *   id = "extra:my_entity",
 *   label = "...",
 *   entity_types = {
 *     "my_entity"
 *   },
 *   group = "extra",
 *   weight = 1
 * )
 */
class MyEntityExtraSelection extends DefaultSelection {

  protected function getAllowedIds() {
    return [...];
  }

  protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
    $query = parent::buildEntityQuery($match, $match_operator);
    $query->condition('id', $this->getAllowedIds(), 'IN');
    return $query;
  }

  public function validateReferenceableNewEntities(array $entities) {
    $entities = parent::validateReferenceableNewEntities($entities);
    $allowed = $this->getAllowedIds();
    return array_filter($entities, function ($entity) {
      return in_array($entity->id(), $allowed);
    });
  }

}

I'd like to call it extra:my_entity because I don't want this filtering to occur by default, every time I use it, only when I refer to it using the 'handler' => 'extra' setting explicitely.

But the core plugin manager gives these errors:

Warning: uasort() expects parameter 1 to be array, null given in Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager->getPluginId() (line 65 of core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionPluginManager.php).
Warning: end() expects parameter 1 to be array, null given in Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager->getPluginId() (line 66 of core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionPluginManager.php).
Warning: key() expects parameter 1 to be array, null given in Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager->getPluginId() (line 67 of core/lib/Drupal/Core/Entity/EntityReferenceSelection/SelectionPluginManager.php).

2 Answers 2

4

As commented, you should not need to provide a deriver for a single entity reference selection plugin. A random plugin ID like extra_my_entity should work. The only condition is that you define the (in this case irrelevant) group property with the same value:

/**
 * Provides an entity reference selection for my_entity.
 *
 * @EntityReferenceSelection(
 *   id = "extra_my_entity",
 *   label = "...",
 *   entity_types = {
 *     "my_entity"
 *   },
 *   group = "extra_my_entity",
 *   weight = 1
 * )
 */
class MyEntityExtraSelection extends DefaultSelection {

See Entity reference selection plugins break when not following a weird ID pattern.

When you extend DefaultSelection then also extend the schema:

config/schema/mymodule.schema.yml

entity_reference_selection.extra_my_entity
  type: entity_reference_selection.default
  label: '...'

Starting a new group

A group in contrast consists of multiple plugin classes. A base class that derives the installed entity types using for example the base plugin ID extra. On installation Drupal will scan the entity types and create for each entity a plugin ID: extra:[entity_type]. You can override the base class by using this plugin ID syntax and the group extra. These group members then don't need to define a deriver, like the core plugins you've seen overriding default:*.

It's not a good idea to combine base and group member in one class, because then deriving the plugin ID as base ends up in a:b:b and other unpredicted things can happen.

6
  • I can see that it shouldn't but it unfortunately does. At least right now for me, I tried all your suggestions, and the only one that doesn't lead to the error is what I described. Deriver included. As your link is about 5 years old, something might have happened since...
    – Gábor
    Commented Nov 12, 2020 at 17:05
  • I mean, yes, I can name both id and group the same (actually, if I don't, if I use a:b for the id and a for the group, the core function will assemble a:b:b at some point) but 1. Deriver 2. the key named label are both necessary.
    – Gábor
    Commented Nov 12, 2020 at 17:06
  • Incidentally, this is how I found out. I started to print out the variables in the plugin manager and suddenly realized that all other plugins have the deriver set but mine. When I added it, it no longer gave the error but it still didn't run my selection code. Then I saw that it still used PhpSelector. Then, finally, I saw the source code comment saying that label is required. :-)
    – Gábor
    Commented Nov 12, 2020 at 17:16
  • You can read in the issue what happened in the last 5 years. They didn't find a solution yet, but they documented the quirks. When using the deriver syntax a:b you normally want to override derived plugins. If this is not your intention then don't use this syntax and you shouldn't need to worry about the deriver class. You can solve this naming pattern problem without deriver.
    – 4uk4
    Commented Nov 12, 2020 at 17:46
  • Sorry, that's what I say. No matter what happened during these 5 years, right now, in front of me, if I remove the deriver, it blows up. If I include it, it works. That's how it is, even if it shouldn't. :-) (Yes, I ended up using the non-colon version. Still. D9.0.7, just for reference.)
    – Gábor
    Commented Nov 12, 2020 at 17:50
3

Update

I needed it again, this time already in Drupal 10. The old tricks are no longer necessary, it works without the deriver and the extra key now.

Earlier

Finally, after some investigation, two required items never documented:

  • unlike the core EntityReferenceSelection plugins that, for some reason, get away without it, you have to provide
deriver = "Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver"

in the plugin annotation.

  • It might be completely unnecessary in your case but you have to make sure your custom entity type has an entity_key named label. If it doesn't, core will use PhpSelector instead of your selector, forcedly.
6
  • It might be that the core plugins you've seen override existing default plugins derived from installed entity types. The question is whether you need a derived plugin at all. Try to not use the : syntax which separates base plugin ID and derivative ID.
    – 4uk4
    Commented Nov 12, 2020 at 14:10
  • @4k4 From experience that doesn't work - you need the namespace or whatever it'd be called to make the plugin work
    – Clive
    Commented Nov 12, 2020 at 14:12
  • @Clive for default:* or a custom plugin ID?
    – 4uk4
    Commented Nov 12, 2020 at 14:18
  • Pretty sure for custom @4k4 - OP's problem sounds identical to one I vaguely remember having last year and coming to the same conclusion
    – Clive
    Commented Nov 12, 2020 at 14:35
  • 1
    @Clive, generating the plugin via drush works because it follows this weird plugin/group naming scheme described here drupal.org/project/drupal/issues/2649712
    – 4uk4
    Commented Nov 12, 2020 at 15:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.