4

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
    – Clive
    Dec 30 '16 at 18:48
  • Right. I was wondering if the injection should happen (calling the \Drupal::service methods) in an overidden createInstance method. Dec 30 '16 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
    – Clive
    Dec 30 '16 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. Dec 30 '16 at 19:12
7

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
  • Thanks @4k4, that is a good example. OP is about FieldTypes not FieldFormatters though. Dec 30 '16 at 19:08
  • ... implementing custom fields in Drupal 8 (types, widgets, formatters). But it's the same for all plugins.
    – 4k4
    Dec 30 '16 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
    – Berdir
    Dec 30 '16 at 22:17
  • 2
    No, it is not possible
    – Berdir
    Oct 10 '18 at 19:38
  • 1
    Yes, since my answer the core example changed in the same way, see git.drupalcode.org/project/drupal/commit/…
    – 4k4
    Nov 6 '19 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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