You are here

gc.mapping-edit.inc in GatherContent 8

Multistep mapping form.

File

forms/gc.mapping-edit.inc
View source
<?php

/**
 * @file
 * Multistep mapping form.
 */
use GatherContent\Template;

/**
 * EDIT MAPPING.
 */

/**
 * Edit mapping form.
 *
 * @inheritdoc
 */
function gc_mapping_edit_form($form, &$form_state, $id) {
  $mapping_entity = \Drupal::entityManager()
    ->getStorage('gc_mapping', array(
    $id,
  ));
  $mapping = reset($mapping_entity);
  $content_types = node_type_get_names();
  $tmp = new Template();
  $template = $tmp
    ->getTemplate($mapping->gc_template_id);
  $new = empty($mapping->data);
  $form = array();
  $form['form_description'] = array(
    '#type' => 'html_tag',
    '#tag' => 'i',
    '#value' => t('Please map your GatherContent Template fields to your Drupal
    Content Type Fields. Please note that a GatherContent field can only be
    mapped to a single Drupal field. So each field can only be mapped to once.'),
  );
  if (!$new) {
    $mapping_data = unserialize($mapping->data);
    $content_type = $content_types[$mapping->content_type];
    $form['info'] = array(
      '#markup' => '<div class="project-name">' . t('Project name: @name', array(
        '@name' => $mapping->gc_project,
      )) . '</div>' . '<div class="gather-content">' . t('GatherContent template: @gc_template', array(
        '@gc_template' => $mapping->gc_template,
      )) . '</div>' . '<div class="drupal-content-type">' . t('Drupal content type: @content_type', array(
        '@content_type' => $content_type,
      )) . '</div>',
    );
    $form['id'] = array(
      '#type' => 'value',
      '#value' => $id,
    );
    $form['updated'] = array(
      '#type' => 'value',
      '#value' => $template->updated_at,
    );
    $form['mapping'] = array(
      '#prefix' => '<div id="edit-mapping">',
      '#suffix' => '</div>',
    );
    foreach ($template->config as $i => $fieldset) {
      if ($fieldset->hidden === FALSE) {
        $form['mapping'][$fieldset->name] = array(
          '#type' => 'fieldset',
          '#title' => $fieldset->label,
          '#collapsible' => TRUE,
          '#collapsed' => $i === 0 ? FALSE : TRUE,
          '#tree' => TRUE,
        );
        if (\Drupal::moduleHandler()
          ->moduleExists('metatag')) {
          $form['mapping'][$fieldset->name]['type'] = array(
            '#type' => 'select',
            '#options' => array(
              'content' => t('Content'),
              'metatag' => t('Metatag'),
            ),
            '#title' => t('Type'),
            '#default_value' => isset($mapping_data[$fieldset->name]['type']) || isset($form_state['values'][$fieldset->name]['type']) ? isset($form_state['values'][$fieldset->name]['type']) ? $form_state['values'][$fieldset->name]['type'] : $mapping_data[$fieldset->name]['type'] : NULL,
            '#ajax' => array(
              'callback' => 'gc_mapping_form_mapping_get_table',
              'wrapper' => 'edit-mapping',
              'method' => 'replace',
              'effect' => 'fade',
            ),
          );
        }
        if (\Drupal::moduleHandler()
          ->moduleExists('entity_translation') && \Drupal::moduleHandler()
          ->moduleExists('title') && entity_translation_node_supported_type($mapping->content_type) && title_field_replacement_enabled('node', $mapping->content_type, 'title')) {
          $form['mapping'][$fieldset->name]['language'] = array(
            '#type' => 'select',
            '#options' => array(
              'und' => t('None'),
            ) + locale_language_list('name'),
            '#title' => t('Language'),
            '#default_value' => isset($mapping_data[$fieldset->name]['language']) ? $mapping_data[$fieldset->name]['language'] : NULL,
          );
        }
        foreach ($fieldset->elements as $gc_field) {
          $d_fields = array();
          if (isset($form_state['triggering_element']['#name'])) {

            // We need different handling for changed fieldset.
            if ($form_state['triggering_element']['#array_parents'][1] === $fieldset->name) {
              if ($form_state['triggering_element']['#value'] === 'content') {
                $d_fields = _filter_fields($gc_field, $mapping->content_type);
              }
              elseif ($form_state['triggering_element']['#value'] === 'metatag') {
                $d_fields = _filter_metatag($gc_field);
              }
            }
            else {
              if ($form_state['values'][$fieldset->name]['type'] === 'content') {
                $d_fields = _filter_fields($gc_field, $mapping->content_type);
              }
              else {
                $d_fields = _filter_metatag($gc_field);
              }
            }
          }
          else {
            if ($mapping_data[$fieldset->name]['type'] === 'content') {
              $d_fields = _filter_fields($gc_field, $mapping->content_type);
            }
            else {
              $d_fields = _filter_metatag($gc_field);
            }
          }
          $form['mapping'][$fieldset->name]['elements'][$gc_field->name] = array(
            '#type' => 'select',
            '#options' => $d_fields,
            '#title' => isset($gc_field->label) ? $gc_field->label : $gc_field->title,
            '#default_value' => isset($mapping_data[$fieldset->name]['elements'][$gc_field->name]) ? $mapping_data[$fieldset->name]['elements'][$gc_field->name] : NULL,
            '#empty_option' => t('- Select -'),
          );
        }
      }
    }
  }
  else {
    $form['info'] = array(
      '#markup' => t('Project name: @name', array(
        '@name' => $mapping->gc_project,
      )) . '<br>' . t('GatherContent template: @gc_template', array(
        '@gc_template' => $mapping->gc_template,
      )),
    );
    $form['id'] = array(
      '#type' => 'value',
      '#value' => $id,
    );
    $form['updated'] = array(
      '#type' => 'value',
      '#value' => $template->updated_at,
    );
    $form['content_type'] = array(
      '#type' => 'select',
      '#title' => t('Drupal Content Types'),
      '#options' => $content_types,
      '#required' => TRUE,
      '#ajax' => array(
        'callback' => 'gc_mapping_form_mapping_get_table',
        'wrapper' => 'edit-mapping',
        'method' => 'replace',
        'effect' => 'fade',
      ),
      '#default_value' => isset($form_state['values']['content_type']) ? $form_state['values']['content_type'] : NULL,
    );
    $form['mapping'] = array(
      '#prefix' => '<div id="edit-mapping">',
      '#suffix' => '</div>',
    );
    if (isset($form_state['values']['content_type'])) {
      foreach ($template->config as $i => $fieldset) {
        if ($fieldset->hidden === FALSE) {
          $form['mapping'][$fieldset->name] = array(
            '#type' => 'fieldset',
            '#title' => $fieldset->label,
            '#collapsible' => TRUE,
            '#collapsed' => $i === 0 ? FALSE : TRUE,
            '#tree' => TRUE,
          );
          if ($i === 0) {
            $form['mapping'][$fieldset->name]['#prefix'] = '<div id="edit-mapping">';
          }
          if (end($template->config) === $fieldset) {
            $form['mapping'][$fieldset->name]['#suffix'] = '</div>';
          }
          if (\Drupal::moduleHandler()
            ->moduleExists('metatag')) {
            $form['mapping'][$fieldset->name]['type'] = array(
              '#type' => 'select',
              '#options' => array(
                'content' => t('Content'),
                'metatag' => t('Metatag'),
              ),
              '#title' => t('Type'),
              '#default_value' => isset($form_state['values'][$fieldset->name]['type']) ? $form_state['values'][$fieldset->name]['type'] : 'content',
              '#ajax' => array(
                'callback' => 'gc_mapping_form_mapping_get_table',
                'wrapper' => 'edit-mapping',
                'method' => 'replace',
                'effect' => 'fade',
              ),
            );
          }
          if (\Drupal::moduleHandler()
            ->moduleExists('entity_translation') && \Drupal::moduleHandler()
            ->moduleExists('title') && entity_translation_node_supported_type($form_state['values']['content_type']) && title_field_replacement_enabled('node', $form_state['values']['content_type'], 'title')) {
            $form['mapping'][$fieldset->name]['language'] = array(
              '#type' => 'select',
              '#options' => array(
                'und' => t('None'),
              ) + locale_language_list('name'),
              '#title' => t('Language'),
              '#default_value' => isset($form_state['values'][$fieldset->name]['language']) ? $form_state['values'][$fieldset->name]['language'] : 'und',
            );
          }
          foreach ($fieldset->elements as $gc_field) {
            $d_fields = array();
            if ($form_state['triggering_element']['#name'] !== 'content_type') {

              // We need different handling for changed fieldset.
              if ($form_state['triggering_element']['#array_parents'][1] === $fieldset->name) {
                if ($form_state['triggering_element']['#value'] === 'content') {
                  $d_fields = _filter_fields($gc_field, $form_state['values']['content_type']);
                }
                elseif ($form_state['triggering_element']['#value'] === 'metatag') {
                  $d_fields = _filter_metatag($gc_field);
                }
              }
              else {
                if ($form_state['values'][$fieldset->name]['type'] === 'content') {
                  $d_fields = _filter_fields($gc_field, $form_state['values']['content_type']);
                }
                else {
                  $d_fields = _filter_metatag($gc_field);
                }
              }
            }
            else {
              $d_fields = _filter_fields($gc_field, $form_state['values']['content_type']);
            }
            $form['mapping'][$fieldset->name]['elements'][$gc_field->name] = array(
              '#type' => 'select',
              '#options' => $d_fields,
              '#title' => isset($gc_field->label) ? $gc_field->label : $gc_field->title,
              '#empty_option' => t("Don't map"),
              '#default_value' => isset($form_state['values'][$fieldset->name]['elements'][$gc_field->name]) ? $form_state['values'][$fieldset->name]['elements'][$gc_field->name] : NULL,
            );
          }
        }
      }
    }
  }
  if (!$new || isset($form_state['values']['content_type'])) {
    $form['mapping']['submit'] = array(
      '#type' => 'submit',
      '#value' => !$new ? t('Update mapping') : t('Create mapping'),
    );
  }
  $form['cancel'] = array(
    '#type' => 'submit',
    '#value' => t('Cancel'),
  );
  return $form;
}

/**
 * Ajax callback for mapping multistep form.
 *
 * @return array
 *   Array of form elements.
 *
 * @inheritdoc
 */
function gc_mapping_form_mapping_get_table($form, &$form_state) {
  return $form['mapping'];
}

/**
 * Validation callback for edit mapping form.
 *
 * In this function, we validate if:
 * - title of title_field is mapped
 * - each field is used only once, if we are mapping single language
 * content type or page
 * OR
 * - each field is used only once per fieldset, if we are mapping multilingual
 * - each language is used only once except `und`.
 *
 * @inheritdoc
 */
function gc_mapping_edit_form_validate($form, &$form_state) {
  if ($form_state['triggering_element']['#id'] == 'edit-submit') {
    $form_definition_elements = array(
      'return',
      'form_build_id',
      'form_token',
      'form_id',
      'op',
    );
    $non_data_elements = array_merge($form_definition_elements, array(
      'gc_template',
      'content_type',
      'id',
      'updated',
    ));
    $mapping_data = array();
    foreach ($form_state['values'] as $key => $value) {
      if (!in_array($key, $non_data_elements) && substr_compare($key, 'tab', 0, 3) === 0) {
        $mapping_data[$key] = $value;
      }
    }

    // Check if is translatable.
    $mapping_entity = \Drupal::entityManager()
      ->getStorage('gc_mapping', array(
      $form_state['values']['id'],
    ));
    $mapping = reset($mapping_entity);
    $content_type = empty($mapping->content_type) ? $form_state['values']['content_type'] : $mapping->content_type;
    $translatable = \Drupal::moduleHandler()
      ->moduleExists('entity_translation') && \Drupal::moduleHandler()
      ->moduleExists('title') && entity_translation_node_supported_type($content_type) && title_field_replacement_enabled('node', $content_type, 'title');

    // Validate if each language is used only once
    // for translatable content types.
    $content_lang = array();
    $metatag_lang = array();
    if ($translatable) {
      foreach ($mapping_data as $tab_id => $tab) {
        $tab_type = isset($tab['type']) ? $tab['type'] : 'content';
        if ($tab['language'] != 'und') {
          if (!in_array($tab['language'], ${$tab_type . '_lang'})) {
            ${$tab_type . '_lang'}[] = $tab['language'];
          }
          else {
            form_set_error($tab_id . '[language]', t('Each language can be used only once'));
          }
        }
      }
    }

    // Validate if each field is used only once.
    $content_fields = array();
    $metatag_fields = array();
    if ($translatable) {
      foreach ($content_lang as $lang) {
        $content_fields[$lang] = array();
      }
      foreach ($metatag_lang as $lang) {
        $metatag_fields[$lang] = array();
      }
      $content_fields['und'] = $metatag_fields['und'] = array();
    }
    foreach ($mapping_data as $tab_id => $tab) {
      $tab_type = isset($tab['type']) ? $tab['type'] : 'content';
      if (isset($tab['elements'])) {
        foreach ($tab['elements'] as $k => $element) {
          if (empty($element)) {
            continue;
          }
          if ($translatable) {
            if (!in_array($element, ${$tab_type . '_fields'}[$tab['language']])) {
              ${$tab_type . '_fields'}[$tab['language']][] = $element;
            }
            else {
              form_set_error($tab_id, t('A GatherContent field can only be mapped to a single Drupal field. So each field can only be mapped to once.'));
            }
          }
          else {
            if (!in_array($element, ${$tab_type . '_fields'})) {
              ${$tab_type . '_fields'}[] = $element;
            }
            else {
              form_set_error($tab_id, t('A GatherContent field can only be mapped to a single Drupal field. So each field can only be mapped to once.'));
            }
          }
        }
      }
    }

    // Validate if at least one field in mapped.
    if (!$translatable && empty($content_fields) && empty($metatag_fields)) {
      form_set_error('form', t('You need to map at least one field to create mapping.'));
    }
    elseif ($translatable && count($content_fields) === 1 && empty($content_fields['und']) && empty($metatag_fields['und']) && count($metatag_fields) === 1) {
      form_set_error('form', t('You need to map at least one field to create mapping.'));
    }

    // Validate if title is mapped for translatable content.
    if ($translatable) {
      foreach ($content_fields as $k => $lang_fields) {
        if (!in_array('field_title', $lang_fields) && $k != \Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED) {
          form_set_error('form', t('You have to map Drupal Title field for translatable content'));
        }
      }
    }
  }
}

/**
 * Submit callback for edit mapping form.
 *
 * @inheritdoc
 */
function gc_mapping_edit_form_submit($form, &$form_state) {
  if ($form_state['triggering_element']['#id'] == 'edit-submit') {
    $form_definition_elements = array(
      'return',
      'form_build_id',
      'form_token',
      'form_id',
      'op',
    );
    $non_data_elements = array_merge($form_definition_elements, array(
      'gc_template',
      'content_type',
      'id',
      'updated',
    ));
    $mapping_data = array();
    foreach ($form_state['values'] as $key => $value) {
      if (!in_array($key, $non_data_elements) && substr_compare($key, 'tab', 0, 3) === 0) {
        $mapping_data[$key] = $value;
      }
    }
    $mapping_entity = \Drupal::entityManager()
      ->getStorage('gc_mapping', array(
      $form_state['values']['id'],
    ));
    $mapping = reset($mapping_entity);
    $new = empty($mapping->data);
    if ($new) {
      $mapping->content_type = $form_state['values']['content_type'];
    }
    $mapping->data = serialize($mapping_data);
    $mapping->updated_drupal = time();
    $mapping->updated_gc = $form_state['values']['updated'];
    $tmp = new Template();
    $template = $tmp
      ->getTemplate($mapping->gc_template_id);
    $mapping->template = serialize($template);
    $mapping
      ->save();

    // We need to modify field for checkboxes and field instance for radios.
    foreach ($template->config as $i => $fieldset) {
      if ($fieldset->hidden === FALSE) {
        foreach ($fieldset->elements as $gc_field) {
          if ($gc_field->type === 'choice_checkbox') {
            if (!empty($mapping_data[$gc_field->name])) {
              $local_options = array();
              foreach ($gc_field->options as $option) {
                $local_options[$option->name] = $option->label;
              }
              $field_data = array(
                'field_name' => $mapping_data[$gc_field->name],
                'settings' => array(
                  'allowed_values' => $local_options,
                ),
              );
              try {
                $field_data
                  ->save();
              } catch (Exception $e) {

                // Log something.
              }
            }
          }
          elseif ($gc_field->type === 'choice_radio') {
            if (!empty($mapping_data[$gc_field->name])) {
              $local_options = array();
              foreach ($gc_field->options as $option) {
                if ($option != end($gc_field->options)) {
                  $local_options[] = $option->name . "|" . $option->label;
                }
              }
              $instance = field_read_instance('node', $mapping_data[$gc_field->name], $mapping->content_type);

              // Make the change.
              $instance['widget']['settings']['available_options'] = implode("\n", $local_options);

              // Save the instance.
              $instance
                ->save();
            }
          }
        }
      }
    }
    if ($new) {
      drupal_set_message(t('Mapping has been created.', array(
        '@id' => $form_state['values']['id'],
      )));
    }
    else {
      drupal_set_message(t('Mapping has been updated.', array(
        '@id' => $form_state['values']['id'],
      )));
    }
  }
  drupal_goto('admin/config/gc/mapping');
}

/**
 * Helper function.
 *
 * Use for filtering only equivalent fields.
 *
 * @param object $gc_field
 *   Type of field in GatherContent.
 * @param string $content_type
 *   Name of Drupal content type.
 *
 * @return array
 *   Associative array with equivalent fields.
 */
function _filter_fields($gc_field, $content_type) {
  $mapping_array = array(
    'files' => array(
      'file',
      'image',
    ),
    'section' => array(
      'text_long',
    ),
    'text' => array(
      'text',
      'text_long',
      'text_with_summary',
    ),
    'choice_radio' => array(
      'text',
    ),
    'choice_checkbox' => array(
      'list_text',
    ),
  );
  $instances = field_info_instances('node', $content_type);
  $fields = array();

  // Fields.
  foreach ($instances as $name => $instance) {
    $field = field_info_field($instance['field_name']);
    if (in_array($field['type'], $mapping_array[$gc_field->type])) {

      // Constrains:
      // - do not map plain text (Drupal) to rich text (GC).
      // - do not map radios (GC) to text (Drupal),
      // if widget isn't provided by select_or_other module.
      // - do not map section (GC) to plain text (Drupal).
      switch ($gc_field->type) {
        case 'text':
          if (!$instance['settings']['text_processing'] && !$gc_field->plain_text || $instance['widget']['module'] === 'select_or_other') {
            continue 2;
          }
          break;
        case 'choise_radio':
          if ($instance['widget']['module'] !== 'select_or_other') {
            continue 2;
          }
          break;
        case 'section':
          if (!$instance['settings']['text_processing']) {
            continue 2;
          }
          break;
      }
      $fields[$instance['field_name']] = $instance['label'];
    }
  }
  if ($gc_field->type === 'text' && $gc_field->plain_text && (!\Drupal::moduleHandler()
    ->moduleExists('title') || !title_field_replacement_enabled('node', $content_type, 'title'))) {
    $fields['title'] = 'Title';
  }
  return $fields;
}

/**
 * Return only supported metatag fields.
 *
 * @param object $gc_field
 *   Object of field from GatherContent.
 *
 * @return array
 *   Array of supported metatag fields.
 */
function _filter_metatag($gc_field) {
  if ($gc_field->type === 'text' && $gc_field->plain_text) {
    return array(
      'title' => t('Title'),
      'description' => t('Description'),
      'abstract' => t('Abstract'),
      'keywords' => t('Keywords'),
    );
  }
  else {
    return array();
  }
}

Functions

Namesort descending Description
gc_mapping_edit_form Edit mapping form.
gc_mapping_edit_form_submit Submit callback for edit mapping form.
gc_mapping_edit_form_validate Validation callback for edit mapping form.
gc_mapping_form_mapping_get_table Ajax callback for mapping multistep form.
_filter_fields Helper function.
_filter_metatag Return only supported metatag fields.