Override existing Configuration entity types - Drupal 8

neha   |  22nd November, 2017

Why do we need to override Config Entity Types?

  1. By default, Vocabulary list displays all the vocabularies. In case we want to restrict certain roles from viewing certain vocabularies. Overriding that Class(VocabularyListBuilder) function would be the solution to display specific/no/all vocabularies.

  2. Let's assume we need to specify vocabulary-path for each vocabulary apart from name, title, description, vid etc. In this case we would need to override the default Vocabulary Form of taxonomy_vocabulary config entity type.

  3. Suppose we want to custom access check for views on the basis of role/user/views operation or whatever, we would need to override ViewsAccessControllerhandler of view configEntityType and write our own logic.

  4. Another use case can be, if we want to display all the image fields which use image style being deleted, on confirm text message, we again need to override ImageStyleFlushForm class and redefine getconfirmText function.

In short, to customise and meet our dynamic requirements which may not be supported by config entity type definition as a part of @ConfigEntityType annotations in core or contributed modules, we need to override existing config entity types and write some custom code :).

How can we override Config Entity Types?

Entity types use object based annotation unlike array based annotation which is commonly used. Also, Unlike Content Entity Types where every thing is a field, NOTHING is a field for Configuration Entity type.

Every Drupal config entity type is defined as a particular ConfigEntityType Annotation. Entity controller is completely different from the Controller of MVC pattern. To avoid this confusion in terminology Entity Controllers are termed as handlers, each form related to a particular entity type say taxonomy_vocabulary is declared inside handlers with form key. 

In this article, will take an example of adding custom form elements to config entity type forms to explain this.

In case we need to add a custom element to any of these forms, we need to follow these 2 steps:

I) Set a new handler class specific to that form.

  1. Implement hook_entity_type_alter(array &$entity_types).
  2. Set new handler class as : 
    $entity_types[{id}]->setHandlerClass('form',
     ['{form_type}' => 'Drupal\my_module\MyModuleForm',
     '....',
     '....'
     ]);

    where, id = configEntityType id,  form_type eg: default, reset, delete etc is whichever form we want to override and MyModuleForm is the Class name of new form we'll define in Step II.
    Here is the sample code of overriding default form of taxonomy vocabulary.

    $entity_types['taxonomy_vocabulary']->setHandlerClass('form',
     ['default' => 'Drupal\my_module\VocabularyForm',
     'reset' => 'Drupal\taxonomy\Form\VocabularyResetForm',
     'delete' => 'Drupal\taxonomy\Form\VocabularyDeleteForm'
     ]);

     

II) Define the class set in Step I.

  1. Extend the actual class of the form we want to add new form elements to. 
    use Drupal\taxonomy\VocabularyForm as VocabularyFormBuilderBase;

    {this is optional, we need to do this to keep the new class name same as base class i.e VocabularyForm}.

    class MyModuleForm extends VocabularyFormBuilderBase 

    OR simply, 

    class MyModuleForm extends VocabularyForm

    This override is important because we need to inherit functions and form elements defined in the parent class i.e VocabularyForm and also add additional feature i.e form element without disturbing the core code. This is purely OOPs concept of inheritance.

  2. We need to override the form function by 
    1. Inheriting the parent elements by parent::form(....) and
    2. Defining the new custom elements as the basic example below:
      $form['third_party_settings']['qed42_textfield'] = array(
       '#type' => 'textfield',
       '#title' => t('QED42 Custom Form Element'),
       '#default_value' => $vocabulary->getThirdPartySetting('my_module', 'qed42_textfield', 'Qed42 textfield default value')
      );  

      Config Entities have by default "getThirdPartySetting()" function { Config entities inherit this function if these extend ConfigEntityBase class which implements ConfigEntityInterface interface which in turn extends ThirdPartySettingsInterface interface}. This thirdParty function allows to set and retrieve a value particularly for a module.

    3. Similarly, we can inherit the save function to save the value of newly added form element with Third Party Settings  as : 

      If the form is set as Tree we need to set value as

      $vocabulary->setThirdPartySetting('my_module', 'qed42_textfield', $form_state->getValue('third_party_settings')['qed42_textfield']);

      else :

      $vocabulary->setThirdPartySetting('my_module', 'qed42_textfield', $form_state->getValue('qed42_textfield'));

      and of course inherit the parent save function. 

    4. We can implement the same logic for extending definition of any existing method  AND can also define new functions inside our new Form.

Any Configuration Entity Type (Date format etc) can be overridden similarly, this can be extended to list_builder, access etc.  Apart from overriding, we can also add new flavours of entity controller using the above steps.

 

 

Looking for a Drupal partner ?

We are drupal 8 ready