5

I am implementing custom fields in Drupal 8 (types, widgets, formatters).

@FieldType plugins are instantiated by their respective plugin manager (\Drupal\Core\Field\FieldTypePluginManager) which does not care about dependency injection. That is possible for both @FieldFormatter and @FieldWidget plugins if they only implement \Drupal\Core\Plugin\ContainerFactoryPluginInterface.

What would be the alternative way to inject a dependency into a @FieldType plugin?

Notes

4
  • I don't think it's supported. e.g. FieldItemBase::view() uses $view_builder = \Drupal::entityManager()->getViewBuilder($this->getEntity()->getEntityTypeId()) even though the entity manager is injectable. I wouldn't have thought that's a mistake/oversight Commented Dec 30, 2016 at 18:48
  • Right. I was wondering if the injection should happen (calling the \Drupal::service methods) in an overidden createInstance method. Commented Dec 30, 2016 at 18:53
  • It wouldn't really be injection any more if the called class is instantiating its own service objects rather than being provided with them...not trying to nitpick or anything but IoC isn't IoC unless that control stays inverted :) The createInstance method sounds like as good a place as any but I might be wrong Commented Dec 30, 2016 at 18:56
  • 2
    Thanks for not nitpicking :). I do agree however regarding IoC, hence came my question in the first place :-) Not having DI options for @FieldType seems odd, especially when writing unit tests. Commented Dec 30, 2016 at 19:12

2 Answers 2

9

An example for a field formatter plugin with dependency injections. This works differently from services. First parameter injected is the container to get all services needed.

Drupal\Core\Field\Plugin\Field\FieldFormatter

class StringFormatter extends FormatterBase implements ContainerFactoryPluginInterface { /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Constructs a StringFormatter instance. * * @param string $plugin_id * The plugin_id for the formatter. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The definition of the field to which the formatter is associated. * @param array $settings * The formatter settings. * @param string $label * The formatter label display setting. * @param string $view_mode * The view mode. * @param array $third_party_settings * Any third party settings settings. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager) { parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings); $this->entityTypeManager = $entity_type_manager; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $configuration['label'], $configuration['view_mode'], $configuration['third_party_settings'], $container->get('entity_type.manager') ); } 
15
  • 1
    Thanks @4k4, that is a good example. OP is about FieldTypes not FieldFormatters though. Commented Dec 30, 2016 at 19:08
  • ... implementing custom fields in Drupal 8 (types, widgets, formatters). But it's the same for all plugins. Commented Dec 30, 2016 at 19:09
  • 3
    Because FieldType plugins are essentially typed data plugins and are instantiated through that and typed data currently doesn't support this, it would need its own interface as it has special constructor arguments. See drupal.org/node/2053415 Commented Dec 30, 2016 at 22:17
  • 3
    No, it is not possible Commented Oct 10, 2018 at 19:38
  • 1
    Yes, since my answer the core example changed in the same way, see git.drupalcode.org/project/drupal/commit/… Commented Nov 6, 2019 at 14:54
0

The accepted answer works for the field widget and field formatter classes. The actual @fieldType definition class constructor requires this signature:

public function __construct( \Drupal\Core\TypedData\ComplexDataDefinitionInterface $definition, $name = NULL, \Drupal\Core\TypedData\TypedDataInterface $parent = NULL ) 

This works for Drupal 8, 9 and 10. For an example, refer to the FieldItemBase class.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.