You are here

DynamicFilterForm.php in Feed Import 8

File

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

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

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AfterCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Ajax\BeforeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Component\Utility\Unicode;
use Drupal\feed_import_base\FeedImport;
class DynamicFilterForm extends FormBase {

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

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $fid = NULL) {
    $this->feed = FeedImport::loadFeed($fid);
    if (is_null($form_state
      ->getValues())) {
      drupal_set_message(t('Dynamic filter functions are created using eval() which can be dangerous for import!'), 'warning');
    }
    $form['description'] = array(
      '#markup' => t('If possible please use a php file including filters (see Filter settings).') . '<br>' . t('Import will not start if any of these functions have syntax errors. If you have problems please check logs.') . '<br>' . '<strong>' . t('If an error occurs on runtime in one of these functions the whole script stops immediately, resulting a broken import process!') . '<br>' . t('Main purpose of these filter functions is testing.') . '<br>' . '</strong>' . '<i>' . t('Ok, eval() can be generally dangerous, but Feed Import assumes that access is enabled only for administrator.') . '</i>',
    );
    $form['fields'] = array(
      '#type' => 'container',
      '#tree' => TRUE,
      '#attributes' => array(
        'id' => 'feed_import_func_fields',
      ),
    );
    $func = 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];
        $func += $this
          ->generateFunctionItem($i, $field);
        unset($field);
      }
      unset($fv);
    }
    else {
      $current_item = -1;
      foreach ($this->feed->settings['functions'] as &$field) {
        $current_item++;
        $func += $this
          ->generateFunctionItem($current_item, $field, TRUE);
      }
      unset($field);
    }
    $trigger = $form_state
      ->getTriggeringElement();
    $cbk = isset($trigger['#name']) ? $trigger['#name'] : '';
    if ($cbk == 'add_new_func') {
      $fv = $form_state
        ->getValue('fields');
      $form_state
        ->set('field_added', FALSE);
      if ($field = Unicode::strtolower($form_state
        ->getValue('func'))) {
        $i = -1;
        $exists = FALSE;
        while (++$i <= $current_item) {
          if (isset($fv['container_' . $i]['name']) && $fv['container_' . $i]['name'] == $field) {
            $exists = TRUE;
            break;
          }
        }
        if (!$exists) {
          $form_state
            ->set('field_added', TRUE);
          $current_item++;
          $func += $this
            ->generateFunctionItem($current_item, array(
            'name' => $field,
            'args' => '',
            'body' => '',
          ));
        }
      }
    }
    elseif (preg_match('/remove_container_([0-9]{1,9})/', $cbk, $match)) {

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

    // Add fields.
    $form['fields'] += $func;
    $form['func'] = array(
      '#type' => 'textfield',
      '#title' => t('Function name'),
      '#attributes' => array(
        'id' => 'func-name',
      ),
      '#description' => t('Name must start with underscore and can contain only alphanumeric chars or underscores.'),
      '#prefix' => '<div id="func-container">',
      '#suffix' => '</div>',
    );
    $form['add_new_func'] = array(
      '#type' => 'button',
      '#name' => 'add_new_func',
      '#value' => t('Add function'),
      '#ajax' => array(
        'event' => 'click',
        'method' => 'replaceWith',
        'callback' => array(
          $this,
          'ajaxAddItem',
        ),
        'wrapper' => 'feed_import_func_fields',
      ),
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#name' => 'save',
      '#value' => t('Save functions'),
    );

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

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    if ($form_state
      ->getValue('func') && !preg_match('/^_[a-z0-9_]+$/i', $form_state
      ->getValue('func'))) {
      $form_state
        ->setError($form['func'], t('Name must start with underscore and can contain only alphanumeric chars or underscores.'));
      $form['add_new_func']['#ajax']['wrapper'] = 'func-container';
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $v = $form_state
      ->getValues();
    if (!$this->feed) {
      return;
    }
    $funcs = array();
    for ($i = 0; $i <= $form_state
      ->get('current_item'); $i++) {
      if (empty($v['fields']['container_' . $i]['name'])) {
        continue;
      }
      $f = $v['fields']['container_' . $i];
      unset($f['remove_container_' . $i]);
      $f = array_map('trim', $f);
      if ($f['name'] && $f['body']) {
        $funcs[] = $f;
      }
    }
    $this->feed->settings['functions'] = $funcs;
    if (FeedImport::saveFeed($this->feed)) {
      drupal_set_message(t('Feed saved'));
    }
  }

  /**
   * Generates function fields.
   */
  protected function generateFunctionItem($pos, array $values, $collapsed = FALSE) {
    if (!preg_match('/^_[a-z0-9_]+$/i', $values['name'])) {
      return array();
    }
    $container = 'container_' . $pos;
    $item[$container] = array(
      '#type' => 'fieldset',
      '#title' => t('Function @name', array(
        '@name' => $values['name'],
      )),
      '#collapsible' => TRUE,
      '#collapsed' => $collapsed,
      '#attributes' => array(
        'id' => 'item_container_' . $pos,
      ),
    );
    $container =& $item[$container];
    $container['name'] = array(
      '#type' => 'textfield',
      '#title' => t('Name'),
      '#description' => t('Name must start with underscore and can contain only alphanumeric chars or underscores.'),
      '#default_value' => $values['name'],
      '#attributes' => array(
        'id' => 'func_name_' . $pos,
      ),
    );
    $container['args'] = array(
      '#type' => 'textfield',
      '#title' => t('Parameters'),
      '#description' => t('Use variable names separated by comma, like: $a, $b'),
      '#default_value' => $values['args'],
    );
    $container['body'] = array(
      '#type' => 'textarea',
      '#rows' => 5,
      '#title' => t('Body'),
      '#description' => t('Write only the function body. Do not forget to return a value.'),
      '#default_value' => $values['body'],
    );
    $container['remove_container_' . $pos] = array(
      '#type' => 'button',
      '#name' => 'remove_container_' . $pos,
      '#value' => t('Remove function'),
      '#ajax' => array(
        'event' => 'click',
        'wrapper' => 'item_container_' . $pos,
        'callback' => array(
          $this,
          'ajaxRemoveItem',
        ),
        'method' => 'replaceWith',
      ),
    );
    return $item;
  }

  /**
   * Ajax callback to add a new item
   */
  public function ajaxAddItem(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    if ($form_state
      ->get('field_added')) {
      $selector = '#' . $form['add_new_func']['#ajax']['wrapper'];
      $content = $form['fields']['container_' . $form_state
        ->get('current_item')];
      $response
        ->addCommand(new AfterCommand($selector, $content));
    }
    $status = array(
      '#type' => 'status_messages',
    );
    $response
      ->addCommand(new ReplaceCommand('#func-container', $form['func']));
    $response
      ->addCommand(new RemoveCommand('div.messages'));
    $response
      ->addCommand(new BeforeCommand('.region-highlighted', $status));
    return $response;
  }

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

    // Return empty string
    return array(
      '#markup' => '',
    );
  }

}

Classes

Namesort descending Description
DynamicFilterForm