Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
novicell/custom_forms / src / Form / CustomFormFieldForm.php
Size: Mime:
<?php

namespace Drupal\custom_forms\Form;

use Drupal\Component\Datetime\Time;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\custom_forms\CustomFormItemFactory;
use Drupal\custom_forms\CustomFormsFieldMappingManager;
use Drupal\custom_forms\CustomFormsFieldTypeManager;
use Drupal\custom_forms\CustomFormItem;
use Drupal\custom_forms\Entity\CustomForm;
use Drupal\custom_forms\Entity\CustomFormType;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class CustomFormFieldForm
 *
 * Form for adding new fields to the custom form.
 *
 * @package Drupal\custom_forms\Form
 */
class CustomFormFieldForm extends FormBase {

  /**
   * The custom forms field type manager.
   *
   * @var CustomFormsFieldTypeManager $fieldTypeManager
   */
  protected $fieldTypeManager;

  /**
   * The custom forms field mapping manager.
   *
   * @var CustomFormsFieldMappingManager $fieldMappingManager
   */
  protected $fieldMappingManager;

  /**
   * The factory in charge of CRUD operations for custom form items.
   *
   * @var \Drupal\custom_forms\CustomFormItemFactory
   */
  protected $itemFactory;

  /**
   * @inheritDoc
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('plugin.manager.custom_forms_field_types'),
      $container->get('plugin.manager.custom_forms_field_mappings'),
      $container->get('custom_forms.factory.item')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function __construct(CustomFormsFieldTypeManager $field_type_manager, CustomFormsFieldMappingManager $field_mapping_manager, CustomFormItemFactory $item_factory) {
    $this->fieldTypeManager = $field_type_manager;
    $this->fieldMappingManager = $field_mapping_manager;
    $this->itemFactory = $item_factory;
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'custom_form_field_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) : array {
    $attributes = \Drupal::request()->attributes;

    /** @var \Drupal\custom_forms\CustomFormInterface $custom_form */
    $custom_form        = $attributes->get('custom_form');
    $available_types    = $this->fieldTypeManager->getDefinitions();
    $available_mappings = $this->fieldMappingManager->getDefinitions();

    if (count($available_types) > 0 && count($available_mappings) > 0) {
      $form['form'] = [
        '#type' => 'value',
        '#value' => $custom_form
      ];

      $form['label'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Label'),
        '#placeholder' => $this->t('Label'),
        '#description' => $this->t('The label shown above the field.'),
        '#required' => TRUE,
        '#weight' => -100,
      ];

      $form['machine_name'] = [
        '#type' => 'machine_name',
        '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
        '#machine_name' => [
          'exists' => '\Drupal\custom_forms\CustomFormItemFactory::itemMachineNameExists',
          'source' => ['label'],
        ],
        '#weight' => -99,
        '#description' => $this->t('A unique machine-readable name for this field. It must only contain lowercase letters, numbers, and underscores.'),
      ];

      $form['message'] = ['#markup' => $this->t('Please select the field type and mapping you want to use in the form.')];

      $field_types = $this->itemFactory->getCompatibleFields($custom_form);

      $form['field_type'] = [
        '#type' => 'select',
        '#title' => $this->t('Field type'),
        '#description' => $this->t('Select the field type to use.'),
        '#required' => TRUE,
        '#empty_option' => '- ' . $this->t('Choose field type') . ' -',
        '#options' => $field_types,
        '#ajax' => [
          'callback' => '::update_available_mappings',
          'wrapper' => 'mappings-wrapper',
          'event' => 'change',
          'progress' => [
            'type' => 'throbber',
            'message' => $this->t('Getting compatible mappings...')
          ],
        ],
      ];

      $form['mappings-wrapper'] = [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#attributes' => [
          'id' => 'mappings-wrapper'
        ],
      ];

      $form['mappings-wrapper']['mapping'] = [
        '#type' => 'select',
        '#disabled' => TRUE,
        '#title' => $this->t('Mapping'),
        '#description' => $this->t('Select the mapping to use.'),
        '#required' => TRUE,
        '#empty_option' => '- ' . $this->t('Choose mapping') . ' -',
      ];

      if (!empty($form_state->getValue('field_type'))) {
        $compatible_mappings = $this->itemFactory->getCompatibleMappings($custom_form, $form_state->getValue('field_type'));
        $mapping_options = [];

        // Generate the options array.
        foreach ($compatible_mappings as $mapping_id => $mapping_definition) {
          $mapping_options[$mapping_id] = $mapping_definition['label'];
        }

        if (count($compatible_mappings) > 0) {
          $form['mappings-wrapper']['mapping']['#options'] = $mapping_options;
          $form['mappings-wrapper']['mapping']['#disabled'] = FALSE;

          if (count($compatible_mappings) === 1) {
            $form['mappings-wrapper']['mapping']['#disabled'] = TRUE;
            $form['mappings-wrapper']['mapping']['#value'] = key($mapping_options);
            $form['mappings-wrapper']['mapping']['#default_value'] = key($mapping_options);
            $form['mappings-wrapper']['mapping']['#description'] = $compatible_mappings[key($mapping_options)]['description'];
          }

        }
        else {
          // Show an error message to the user to avoid confusion.
          $this->messenger()->addError($this->t('No compatible field mappings were found for the selected field type.'));
        }
      }

    } else {

      $messages = [];
      if (count($available_types) <= 0) {
        $messages[] = $this->t('No field type plugins found.');
      }

      if (count($available_mappings) <= 0) {
        $messages[] = $this->t('No field mapping plugins found.');
      }

      $form['message'] = [
        '#type' => 'markup',
        '#markup' => $this->t('Unable to load form, see reason(s) below.'),
        'reasons' => [
          '#theme' => 'item_list',
          '#list_type' => 'ul',
          '#items' => $messages,
        ]
      ];
    }

    $form['actions'] = [
      '#type' => 'actions',
    ];

    if (count($available_types) > 0 && count($available_mappings) > 0) {
      $form['actions']['create'] = [
        '#type' => 'submit',
        '#value' => $this->t('Create'),
        '#attributes' => [
          'class' => [
            'button',
            'button-action',
            'button--primary',
          ]
        ],
      ];
    }

    $form['actions']['cancel'] = [
      '#type' => 'link',
      '#title' => $this->t('Cancel'),
      '#url' => Url::fromRoute('entity.custom_form.fields_form', ['custom_form' => $custom_form->id()]),
      '#attributes' => [
        'class' => [
          'button',
          'button-action',
          'button--secondary',
        ],
      ],
      '#limit_validation_errors' => [],
    ];

    if (count($available_types) <= 0 || count($available_mappings) <= 0) {
      $form['actions']['cancel']['#title'] = $this->t('Back');
      $form['actions']['cancel']['#attributes']['style'][] = 'margin-left: 0;';
      $form['actions']['cancel']['#attributes']['class'] = [
        'button',
        'button-action',
        'button--primary',
      ];
    }

    return $form;
  }

  /**
   * Updates the render array for field mappings through ajax callback.
   *
   * @param array $form
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *
   * @return array
   */
  public function update_available_mappings(array &$form, FormStateInterface $form_state) {
    return $form['mappings-wrapper'];
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $attributes = \Drupal::request()->attributes;
    $values = $form_state->cleanValues()->getValues();

    /** @var CustomForm $custom_form */
    $custom_form = $attributes->get('custom_form');
    $field_definition = $this->fieldTypeManager->getDefinition($values['field_type']);

    /** @var Time $time */
    $time = \Drupal::service('datetime.time');
    $timestamp = $time->getCurrentTime();

    // Construct the basic settings.
    $settings = [
      'label' => $values['label'],
      'machine_name' => $values['machine_name']
    ];
    if (isset($field_definition['no_ui']) && (boolean) $field_definition['no_ui']) {
      $settings['no_ui'] = TRUE;
    }

    // Create a new custom form revision since we are modifying it by adding a new field.
    $revision_saved = FALSE;
    $custom_form->setNewRevision(TRUE);
    $custom_form->setRevisionTranslationAffected(TRUE); // for some reason required for log messages to show up?
    $custom_form->setRevisionLogMessage($this->t('Added new field: @field-label', ['@field-label' => $values['label']]));
    $custom_form->setRevisionCreationTime(\Drupal::time()->getRequestTime());
    $custom_form->setRevisionUserId(\Drupal::currentUser()->id());
    try {
      $custom_form->save();
      $revision_saved = TRUE;
    } catch (EntityStorageException $e) {
      $error_message = $this->t('Failed during creation of new revision. Message = %message', [
        '%message' => $e->getMessage()
      ]);
      \Drupal::logger('Custom Forms')->error($error_message);
      $this->messenger()->addError($this->t('Failed during creation of new revision, please try again. If it continues please contact an administrator.'));
    }

    // We only want to create the new field if the revision was able to be saved.
    if ($revision_saved) {
      $item = new CustomFormItem($custom_form->id(), $custom_form->getLoadedRevisionId(), $timestamp, $timestamp, $custom_form->language()->getId(), 'field', $values['field_type'], $values['machine_name'], serialize($settings), serialize([]), $values['mapping'], 1000);

      try {
        $item->getPlugin()->setEmptyDefaults($item);
        $item->save();
        $this->messenger()->addMessage($this->t('%item-label was successfully created.', ['%item-label' => $values['label']]));
      } catch (\Exception $e) {
        $error_message = $this->t('Field saving failed. Message = %message. Trace = @trace', [
          '%message' => $e->getMessage(),
          '@trace' => $e->getTraceAsString()
        ]);
        \Drupal::logger('Custom Forms')->error($error_message);
        $this->messenger()->addError($this->t('Failed during creation of new field, please try again. If it continues please contact an administrator.'));
      }
    }

    $form_state->setRedirect('entity.custom_form.fields_form', ['custom_form' => $custom_form->id()]);
  }
}