You are here

FieldsForm.php in Feed Import 8

File

src/Form/FieldsForm.php
View source
<?php

/**
 * @file
 * Contains \Drupal\feed_import\Form\FieldsForm
 */
namespace Drupal\feed_import\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\feed_import_base\FeedImport;
use Drupal\feed_import_base\FeedImportProcessor;
class FieldsForm extends FormBase {

  /**
   * The feed being edited.
   *
   * @var object containing feed settings.
   */
  protected $feed;

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $fid = NULL) {
    $this->feed = FeedImport::loadFeed($fid);

    // Set uniq path.
    $form['uniq'] = array(
      '#type' => 'textfield',
      '#default_value' => $this->feed->settings['uniq_path'],
      '#title' => t('Enter path to unique id'),
      '#description' => t('Used to monitor items for updates.'),
    );

    // Fields list
    $form['fields'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'id' => 'feed_import_path_fields',
      ),
      '#tree' => TRUE,
    );
    $paths = $fields = array();
    $current_item = $form_state
      ->get('current_item');
    if (!is_null($current_item)) {
      $fv = $form_state
        ->getValue('fields');
      for ($i = 0; $i <= $current_item; $i++) {
        if (!isset($fv['container_' . $i])) {
          continue;
        }
        $field =& $fv['container_' . $i];
        $fields[] = $field['field'];
        $paths += $this
          ->generatePathItem($i, $field);
        unset($field);
      }
      unset($fv);
    }
    else {
      $current_item = -1;
      foreach ($this->feed->settings['fields'] as &$field) {
        $current_item++;
        $fields[] = $field['field'];
        $paths += $this
          ->generatePathItem($current_item, $field, TRUE);
      }
      unset($field);
    }
    $fv = $form_state
      ->getValues();
    $trigger = $form_state
      ->getTriggeringElement();
    if ($trigger) {
      if ($trigger['#name'] == 'add_new_item') {
        $form_state
          ->set('field_added', FALSE);
        $field = $fv['add_new_item_mode'] ? 'add_new_item_field' : 'add_new_item_manual';
        if ($field = Unicode::strtolower($fv[$field])) {
          $i = -1;
          $exists = FALSE;
          while (++$i <= $form_state
            ->get('current_item')) {
            if (isset($fv['fields']['container_' . $i]['field']) && $fv['fields']['container_' . $i]['field'] == $field) {
              $exists = TRUE;
              break;
            }
          }
          if (!$exists) {
            $form_state
              ->set('field_added', TRUE);
            $current_item++;
            $paths += $this
              ->generatePathItem($current_item, array(
              'field' => $field,
              'default_value' => '',
              'default_action' => FeedImportProcessor::ACTION_DEFAULT_VALUE,
              'update_mode' => FeedImportProcessor::UPDATE_COMBINE,
              'paths' => '',
            ));
          }
        }
      }
      elseif (preg_match('/remove_container_([0-9]{1,9})/', $trigger['#name'], $match)) {

        // Delete container.
        unset($paths['container_' . $match[1]]);
      }
    }
    $form_state
      ->set('current_item', $current_item);

    // Add fields.
    $form['fields'] += $paths;
    unset($paths);

    // Generate field options.
    $opts = FeedImport::getEntityInfo($this->feed->entity);
    $opts = array_merge($opts->properties, array_keys($opts->fields));
    $opts = array_diff($opts, $fields);
    $opts = array_combine($opts, $opts);

    // Add new field mode.
    $form['add_new_item_mode'] = array(
      '#type' => 'checkbox',
      '#title' => t('Use defined fields'),
      '#default_value' => TRUE,
      '#id' => 'add-new-item-mode',
    );

    // Add entity fields.
    $form['add_new_item_field'] = array(
      '#type' => 'select',
      '#options' => $opts,
      '#title' => t('Select defined field'),
      '#description' => t('Select field name and click "' . t('Add field') . '" button'),
      '#id' => 'add-new-item-field',
      '#states' => array(
        'visible' => array(
          ':input[name=add_new_item_mode]' => array(
            'checked' => TRUE,
          ),
        ),
      ),
    );

    // Manual field.
    $form['add_new_item_manual'] = array(
      '#type' => 'textfield',
      '#title' => t('Enter field name'),
      '#description' => t('Write field name and click "@name" button', array(
        '@name' => t('Add field'),
      )),
      '#id' => 'add-new-item-manual',
      '#states' => array(
        'visible' => array(
          ':input[name=add_new_item_mode]' => array(
            'checked' => FALSE,
          ),
        ),
      ),
    );

    // Add new field button.
    $form['add_new_item'] = array(
      '#type' => 'button',
      '#name' => 'add_new_item',
      '#value' => t('Add field'),
      '#inline' => TRUE,
      '#ajax' => array(
        'event' => 'click',
        'callback' => array(
          $this,
          'ajaxAddItem',
        ),
        'wrapper' => 'feed_import_path_fields',
        'method' => 'append',
      ),
    );

    // Submit buttons.
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Save feed'),
    );

    // Add js.
    $form['#attached'] = array(
      'library' => array(
        'feed_import/behaviors',
      ),
    );
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $v = $form_state
      ->getValues();
    if (!$this->feed) {
      return;
    }
    $e = FeedImport::getEntityInfo($this->feed->entity);
    $fields = array();
    for ($i = 0; $i <= $form_state
      ->get('current_item'); $i++) {
      if (empty($v['fields']['container_' . $i]['field'])) {
        continue;
      }
      $f =& $v['fields']['container_' . $i];
      $fields[$f['field']] = array(
        'field' => $f['field'],
        'column' => isset($e->fields[$f['field']]),
        'paths' => array_filter(preg_split('/\\r?\\n/', $f['paths']), 'strlen'),
        'default_action' => (int) $f['default_action'],
        'default_value' => $f['default_value'],
        'update_mode' => (int) $f['update_mode'],
        'filters' => isset($this->feed->settings['fields'][$f['field']]['filters']) ? $this->feed->settings['fields'][$f['field']]['filters'] : array(),
        'prefilters' => isset($this->feed->settings['fields'][$f['field']]['prefilters']) ? $this->feed->settings['fields'][$f['field']]['prefilters'] : array(),
      );
      unset($f);
    }
    $this->feed->settings['uniq_path'] = $v['uniq'];
    $this->feed->settings['fields'] = $fields;

    // Save feed.
    if (FeedImport::saveFeed($this->feed)) {
      drupal_set_message(t('Feed saved'));
    }
  }

  /**
   * Generate field
   *
   * @param int $pos
   *   Fieldset number
   * @param array $values
   *   Array containing default values
   * @param bool $collapsed
   *   Inicates if fieldset is collapsed
   *
   * @return array
   *   Fieldset containing xpath inputs
   */
  protected function generatePathItem($pos, array $values, $collapsed = FALSE) {
    $container = 'container_' . $pos;
    $item[$container] = array(
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => $collapsed,
      '#title' => isset($values['field']) ? $values['field'] : t('Unspecified field'),
      '#attributes' => array(
        'id' => 'item_container_' . $pos,
      ),
    );
    $container =& $item[$container];
    $container['field'] = array(
      '#type' => 'value',
      '#value' => $values['field'],
    );
    $container['paths'] = array(
      '#type' => 'textarea',
      '#default_value' => is_array($values['paths']) ? implode(PHP_EOL, $values['paths']) : $values['paths'],
      '#title' => t('Paths'),
      '#description' => t('Enter path to item. You can enter multiple paths (one per line) until one passes pre-filter.'),
    );
    $container['default_action'] = array(
      '#type' => 'select',
      '#options' => array(
        FeedImportProcessor::ACTION_DEFAULT_VALUE => t('Provide a default value'),
        FeedImportProcessor::ACTION_DEFAULT_FILTERED_VALUE => t('Provide a filtered default value'),
        FeedImportProcessor::ACTION_IGNORE_FIELD => t('Ignore this field'),
        FeedImportProcessor::ACTION_SKIP_ITEM => t('Skip importing this entity'),
      ),
      '#default_value' => $values['default_action'],
      '#title' => t('Action when filtered result is empty'),
      '#description' => t('If the filtered result is empty you can choose what action to take next.'),
      '#id' => 'default_action_' . $pos,
    );
    $container['default_value'] = array(
      '#type' => 'textarea',
      '#rows' => 2,
      '#default_value' => $values['default_value'],
      '#title' => t('Default value'),
      '#description' => t('If no path passes pre-filter then use a default value.'),
      '#prefix' => '<div style="display: none;" rel="default_action_' . $pos . '">',
      '#suffix' => '</div>',
    );
    $options = \Drupal::moduleHandler()
      ->invokeAll('feed_import_field_merge_classes');
    foreach ($options as &$option) {
      $option = $option['title'];
    }
    $container['update_mode'] = array(
      '#type' => 'select',
      '#options' => $options,
      '#default_value' => $values['update_mode'],
      '#title' => t('Field update mode'),
      '#description' => t('How to update existing entities.'),
    );
    $container['remove_container_' . $pos] = array(
      '#type' => 'button',
      '#name' => 'remove_container_' . $pos,
      '#value' => t('Remove field'),
      '#ajax' => array(
        'event' => 'click',
        'wrapper' => 'item_container_' . $pos,
        'method' => 'replace',
        'callback' => array(
          $this,
          'ajaxRemoveItem',
        ),
      ),
    );
    return $item;
  }

  /**
   * Ajax callback to add a new item
   */
  public function ajaxAddItem(array &$form, FormStateInterface $form_state) {
    if ($form_state
      ->get('field_added')) {
      return $form['fields']['container_' . $form_state
        ->get('current_item')];
    }
    return NULL;
  }

  /**
   * Ajax callback to remove an item
   */
  public function ajaxRemoveItem(array &$form, FormStateInterface $form_state) {

    // Send empty string to remove container.
    return array(
      '#markup' => '',
    );
  }

}

Classes

Namesort descending Description
FieldsForm