View source  
  <?php
namespace Drupal\tooltip_taxonomy\Form;
use Drupal\Component\Plugin\Factory\FactoryInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\tooltip_taxonomy\Services\FieldTypeManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FilterConditionForm extends EntityForm {
  
  protected $entityTypeManager;
  
  protected $entityTypeBundleInfo;
  
  protected $pathCondition;
  
  protected $contentTypeCondition;
  
  protected $fieldTypePluginManager;
  
  protected $fieldTypeManager;
  
  public function __construct(EntityTypeManagerInterface $entityTypeManager, EntityTypeBundleInfoInterface $entity_type_bundle_info, FactoryInterface $plugin_factory, FieldTypePluginManagerInterface $field_type_plugin_manager, FieldTypeManager $field_type_manager) {
    $this->entityTypeManager = $entityTypeManager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
    $this->pathCondition = $plugin_factory
      ->createInstance('request_path');
    $this->contentTypeCondition = $plugin_factory
      ->createInstance('node_type');
    $this->fieldTypePluginManager = $field_type_plugin_manager;
    $this->fieldTypeManager = $field_type_manager;
  }
  
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('entity_type.manager'), $container
      ->get('entity_type.bundle.info'), $container
      ->get('plugin.manager.condition'), $container
      ->get('plugin.manager.field.field_type'), $container
      ->get('tooltip_taxonomy.field_type_manager'));
  }
  
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);
    $condition = $this->entity;
    $form['name'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Name'),
      '#maxlength' => 255,
      '#default_value' => $condition
        ->label(),
      '#description' => $this
        ->t("Name for the filter condition."),
      '#required' => TRUE,
    ];
    $form['cid'] = [
      '#type' => 'machine_name',
      '#default_value' => $condition
        ->id(),
      '#machine_name' => [
        'exists' => [
          $this,
          'exist',
        ],
        'source' => [
          'name',
        ],
      ],
      '#disabled' => !$condition
        ->isNew(),
    ];
    
    $voca_options = [];
    foreach ($this->entityTypeBundleInfo
      ->getBundleInfo('taxonomy_term') as $voc_name => $voc_info) {
      $voca_options[$voc_name] = $voc_info['label'];
    }
    $form['vids'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Vocabularies for tooltips.'),
      '#options' => $voca_options,
      '#default_value' => $condition
        ->get('vids'),
      '#required' => TRUE,
      '#description' => $this
        ->t('Selected vocabularies will be used as the content text of tooltips in following pages or content types for a certain field. If none is checked, there will not be tooltip created.'),
    ];
    $formats = filter_formats();
    $format_options = [];
    foreach ($formats as $format) {
      $format_options[$format
        ->id()] = $format
        ->label();
    }
    $form['formats'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Text formats.'),
      '#options' => $format_options,
      '#default_value' => $condition
        ->get('formats'),
      '#required' => TRUE,
      '#description' => $this
        ->t('Select which formats does this condition applys to.'),
    ];
    
    $view_mode_ids = \Drupal::entityQuery('entity_view_mode')
      ->condition('targetEntityType', 'node')
      ->execute();
    $view_modes = \Drupal::entityTypeManager()
      ->getStorage('entity_view_mode')
      ->loadMultiple($view_mode_ids);
    $view_mode_options = [];
    foreach ($view_modes as $mode) {
      $id = $mode
        ->id();
      $view_mode_options[substr($id, 5)] = $mode
        ->label();
    }
    
    $form['view'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('View modes'),
      '#options' => $view_mode_options,
      '#default_value' => $condition
        ->get('view'),
      '#description' => $this
        ->t('If none is selected, this condition will be applied to all view modes.'),
    ];
    
    $this->pathCondition
      ->setConfiguration($condition
      ->get('path'));
    
    $form['path'] = $this->pathCondition
      ->buildConfigurationForm([], $form_state);
    
    $this->contentTypeCondition
      ->setConfiguration($condition
      ->get('contentTypes'));
    
    $form['node'] = $this->contentTypeCondition
      ->buildConfigurationForm([], $form_state);
    
    unset($form['node']['negate']);
    
    $fields = $this
      ->getExistingFieldStorageOptions();
    if (!empty($fields)) {
      
      $form['field'] = [
        '#type' => 'select',
        '#title' => $this
          ->t('Field'),
        '#options' => $fields,
        '#default_value' => $condition
          ->get('field'),
        '#empty_option' => $this
          ->t('- Select an existing field -'),
        '#multiple' => TRUE,
        '#description' => $this
          ->t('If none is selected, this condition will be applied to all fields.'),
      ];
    }
    return $form;
  }
  
  public function save(array $form, FormStateInterface $form_state) {
    $condition = $this->entity;
    $this->pathCondition
      ->submitConfigurationForm($form['path'], $form_state);
    $this->contentTypeCondition
      ->submitConfigurationForm($form['node'], $form_state);
    
    $this->contentTypeCondition
      ->setConfig('negate', 0);
    foreach ($form_state
      ->getValues() as $key => $value) {
      if ($key === 'vids') {
        $vids = [];
        foreach ($value as $vid) {
          if (!empty($vid)) {
            $vids[] = $vid;
          }
        }
        
        $condition
          ->set('vids', $vids);
      }
      else {
        $condition
          ->set($key, $value);
      }
    }
    
    $condition
      ->set('path', $this->pathCondition
      ->getConfiguration());
    
    $condition
      ->set('contentTypes', $this->contentTypeCondition
      ->getConfiguration());
    $status = $condition
      ->save();
    if ($status) {
      $this
        ->messenger()
        ->addMessage($this
        ->t('Saved the %label Example.', [
        '%label' => $condition
          ->label(),
      ]));
    }
    else {
      $this
        ->messenger()
        ->addMessage($this
        ->t('The %label Example was not saved.', [
        '%label' => $condition
          ->label(),
      ]), MessengerInterface::TYPE_ERROR);
    }
    
    \Drupal::service('cache_tags.invalidator')
      ->invalidateTags([
      'node_view',
    ]);
    $form_state
      ->setRedirect('entity.tooltip_taxonomy.config');
  }
  
  public function exist($id) {
    $entity = $this->entityTypeManager
      ->getStorage('filter_condition')
      ->getQuery()
      ->condition('cid', $id)
      ->execute();
    return (bool) $entity;
  }
  
  protected function getExistingFieldStorageOptions() {
    $options = [];
    
    $field_types = $this->fieldTypePluginManager
      ->getDefinitions();
    $fields = $this->entityTypeManager
      ->getStorage('field_storage_config')
      ->loadByProperties([
      'deleted' => FALSE,
      
      'status' => 1,
    ]);
    foreach ($fields as $field_name => $field_storage) {
      
      $field_type = $field_storage
        ->getType();
      $field_key_name = str_replace('.', '-', $field_name);
      if ($field_storage instanceof FieldStorageConfigInterface && $this->fieldTypeManager
        ->isContentField($field_storage
        ->getName()) && $this->fieldTypeManager
        ->isTextField($field_type) && !$field_storage
        ->isLocked()) {
        $options[$field_key_name] = $this
          ->t('@type: @field', [
          '@type' => $field_types[$field_type]['label'],
          '@field' => $field_name,
        ]);
      }
    }
    asort($options);
    return $options;
  }
}