Problem/Motivation

ElementInfoManager does not provide an alterHook definition. This prevents altering element plugin definitions. As more and more contrib provide elements, sometimes it is required to override them for improvements. This is impossible for element plugins.

See alterDefinitions, where it is skipped if there is no alterHook

protected function alterDefinitions(&$definitions) {
    if ($this->alterHook) {
      $this->moduleHandler->alter($this->alterHook, $definitions);
    }
  }

Proposed resolution

Provide an alterHook definition. Invoke \Drupal\Core\Plugin\DefaultPluginManager::alterInfo in the consturctor so that end users can swap element classes.

Remaining tasks

Add patch.

API changes

Adds a new hook.

Release notes snippet

A new hook has been added to allow altering of render element plugins. Read the change record for more.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mglaman created an issue. See original summary.

mglaman’s picture

To accomplish this, I swapped the element manager for a custom class:

<?php

namespace Drupal\mymodule;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Render\ElementInfoManager;
use Drupal\Core\Theme\ThemeManagerInterface;

class AlterableElementManager extends ElementInfoManager {

  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, CacheTagsInvalidatorInterface $cache_tag_invalidator, ModuleHandlerInterface $module_handler, ThemeManagerInterface $theme_manager) {
    parent::__construct($namespaces, $cache_backend, $cache_tag_invalidator, $module_handler, $theme_manager);
    $this->alterInfo('element_definition_info');
  }

}

And then

/**
 * Implements hook_element_info_alter().
 */
function mymodule_element_definition_info_alter(array &$info) {
  if (isset($info['commerce_profile_select'])) {
    $info['commerce_profile_select']['class'] = \Drupal\mymodule\Element\ProfileSelect::class;
    $info['commerce_profile_select']['provider'] = 'mymodule';
  }
}
sime’s picture

Patch to add the alterInfo() call. I've used `form_element_info` to map what a developer would expect it to be called based on @FormElement plugin type but I didn't look deeper.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.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

Issue tags: +Plugin system

Be sure to add a hook example in core/lib/Drupal/Core/Render/theme.api.php, preferably right after hook_element_info_alter().

I'd suggest hook_element_plugin_alter() here, it's not specific to forms.

akalata’s picture

Status: Active » Needs review
FileSize
1.57 KB

Here's a quick patch with an attempt at documentation.

tim.plunkett’s picture

  1. +++ b/core/lib/Drupal/Core/Render/theme.api.php
    @@ -810,6 +810,23 @@ function hook_element_info_alter(array &$info) {
    + * @param array $plugins
    ...
    +function hook_element_plugin_alter(array &$plugins) {
    

    Let's rename this $definitions, seems to be the standard for these hooks.

  2. +++ b/core/lib/Drupal/Core/Render/theme.api.php
    @@ -810,6 +810,23 @@ function hook_element_info_alter(array &$info) {
    +  $plugins['layout_builder']['class'] = '\Drupal\mymodule\Element\MyLayoutBuilderElement';
    

    Great example! :)

There's no need for explicit test coverage here, as it uses the existing DefaultPluginManager::alterInfo() method.

akalata’s picture

Updated based on #7: $plugins to $definitions.

tim.plunkett’s picture

Typo in definitiions.

Also I think this new alter should have a sentence about preferring usage of hook_element_info_alter when possible, since they are slightly different

akalata’s picture

akalata’s picture

Tried editing the patch file manually, missed a step.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Looks great, thanks!

The last submitted patch, 3: drupal_form-element-info-alter-2987208-3.patch, failed testing. View results

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs release note, +Needs change record

I discussed this with @tim.plunkett and we agreed that the API expansion is necessary. This type of thing needs a change record so people know about it and a release notes snippet.

Create a new CR here -> https://www.drupal.org/node/add/changenotice?field_project=3060

Ghost of Drupal Past’s picture

I hit this issue so often I published a workaround at https://gitlab.com/chx_/do2987208 almost a year ago. I will see what I can do to get this across the finish line.

Ghost of Drupal Past’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs release note, -Needs change record
bircher’s picture

Status: Needs review » Reviewed & tested by the community

This now has a release note snippet and a change notice. The patch is simple and looks good to me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

Ideally we'd have test coverage of this too. We could add a hook implementation to element_info_test,module

alexpott’s picture

The test-only patch is the interdiff.

alexpott’s picture

Issue tags: -Needs tests

The last submitted patch, 19: 2987208-19.test-only.patch, failed testing. View results

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Looks great :)

The last submitted patch, 19: 2987208-19.test-only.patch, failed testing. View results

The last submitted patch, 19: 2987208-19.test-only.patch, failed testing. View results

larowlan’s picture

issue credits

  • larowlan committed d68cb07 on 8.8.x
    Issue #2987208 by akalata, alexpott, sime, tim.plunkett, Charlie ChX...
larowlan’s picture

Status: Reviewed & tested by the community » Fixed

Committed d68cb07 and pushed to 8.8.x. Thanks!

Published the change record.

thanks folks

ndobromirov’s picture

Just a late question...
Why introduce new hooks, when there is a viable alternative in D8 - events?

Berdir’s picture

See #2237831: Allow module services to specify hooks and tons of related issues and discussions. In short, the current event system has drawbacks and it wouldn't scale to convert all our current hooks to events. And replacing hooks with events has been pretty much put on old. This added a new hook, agreed, but we have a standard system in place for altering plugin definitions and this uses that.

Status: Fixed » Closed (fixed)

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