denormalizer-8.x-1.x-dev/denormalizer.module

denormalizer.module
<?php

use Drupal\webform\Entity\Webform;

/**
 * @file
 * Denormalizer - module.
 */

use Drupal\Core\Database\Query\Select;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityInterface;
use Drupal\denormalizer\Denormalizer;
use Drupal\denormalizer\Entity\DenormalizerTable;

/**
 * Implements hook_cron().
 *
 * Run or reload periodically.
 */
function denormalizer_cron() {
  $config = \Drupal::service('config.factory')
    ->getEditable('denormalizer.settings');
  if ($config->get('cron_enabled')) {
    $last_run = $config->get('last_run');
    $reset = NULL;
    if ($config->get('reload_every') && ($last_run + $config->get('reload_every') * 60 * 60) <= \Drupal::time()->getRequestTime()) {
      $reset = TRUE;
    }
    elseif ($config->get('run_every') && ($last_run + $config->get('run_every') * 60 * 60) <= \Drupal::time()->getRequestTime()) {
      $reset = FALSE;
    }
    if (!is_null($reset)) {
      $denormalizer = new Denormalizer();
      $denormalizer->build();
      try {
        $denormalizer->execute($reset);
      }
      catch (PDOException $e) {
        if (in_array($e->getCode(), ['42S22', '21S01'])) {
          \Drupal::logger('denormalizer')
            ->info('Different fields detected. Running reload.');
          $denormalizer->execute(TRUE);
        }
      }
      $config->set('last_run', \Drupal::time()->getRequestTime())->save();
      \Drupal::logger('denormalizer')->info('Ran denormalizer.');
    }
  }
}

/**
 * Implements hook_entity_update().
 */
function denormalizer_entity_update(EntityInterface $entity) {
  if ($entity->getEntityType()->getGroup() == 'content') {
    DenormalizerTable::onContentEntityCRUD($entity);
  }
}

/**
 * Implements hook_entity_insert().
 */
function denormalizer_entity_insert(EntityInterface $entity) {
  if ($entity->getEntityType()->getGroup() == 'content') {
    DenormalizerTable::onContentEntityCRUD($entity, TRUE);
  }
}

/**
 * Implements hook_entity_delete().
 */
function denormalizer_entity_delete(EntityInterface $entity) {
  if ($entity->getEntityType()->getGroup() == 'content') {
    DenormalizerTable::onContentEntityCRUD($entity, FALSE, TRUE);
  }
}

/**
 * Get denormalizer info from module implementation.
 *
 * This almost mirrors entity_info() but the 'bundles' key is flat.
 *
 * @return array
 *   Denormalizer info.
 *
 * @throws \Exception
 */
function denormalizer_get_info() {
  $info = \Drupal::moduleHandler()->invokeAll('denormalizer_info');
  $entity_type_manager = \Drupal::entityTypeManager();
  $denormalizer_tbl_storage = $entity_type_manager->getStorage('denormalizer_table');

  /** @var \Drupal\denormalizer\Entity\DenormalizerTableInterface[] $tables */
  $tables = $denormalizer_tbl_storage->loadByProperties([
    'status' => 1,
    // Only use the non entity for this process.
    'source' => 'non_entity',
  ]);
  foreach ($tables as $table) {
    $configuration = $table->getSourceConfiguration();
    $info[$table->getDbTableName()] = [
      'base table' => $table->getBaseTable(),
      'changed_key' => $configuration['changed_key'] ?? '',
      'external' => $configuration['external'],
    ];
  }
  \Drupal::moduleHandler()->alter('denormalizer_info', $info);
  foreach ($info as $target_table => &$entry) {
    if (!isset($entry['bundles'])) {
      $entry['bundles'] = [];
    }
    if (isset($entry['entity_type'])) {
      $entry += (array) $entity_type_manager->getDefinition($entry['entity_type']);
    }
    if (!isset($entry['fields'])) {
      $entry['fields'] = [];
    }
  }
  return $info;
}

/**
 * Get the primary key of a table in the Drupal schema.
 *
 * @param string $dn_table
 *   The dn_table.
 *
 * @return string
 *   The primary key label.
 */
function denormalizer_get_primary_key($dn_table) {
  $d = denormalizer_get_info();
  $dn_info = $d[$dn_table];

  if (isset($d[$dn_table]['primary key'])) {
    // Manually defined primary key.
    return $d[$dn_table]['primary key'];
  }

  if ($dn_table == 'user') {
    // Special case for the user table.
    return 'uid';
  }

  // Drupal defined table.
  // Replaced "$d['schema_module']" by "$d[$dn_table]['schema_module']".
  $schema = drupal_get_module_schema($d[$dn_table]['schema_module'], $d[$dn_table]['base table']);
  if (isset($schema['primary key']) && count($schema['primary key']) == 1) {
    return $schema['primary key'][0];
  }

  if (isset($dn_info['surrogate key'])) {
    return $dn_info['surrogate key'];
  }
}

/**
 * Convert db_select to SQL.
 *
 * Modified from devel module.
 *
 * @param Drupal\Core\Database\Driver\mysql\Select $query
 *   SQL query.
 *
 * @return string
 *   SQL of db_select object.
 */
function denormalizer_dpq(Select $query) {
  $config = \Drupal::service('config.factory')
    ->getEditable('denormalizer.settings');
  if (method_exists($query, 'preExecute')) {
    $query->preExecute();
  }
  $sql = (string) $query;
  $quoted = [];
  $connection = Database::getConnection();
  foreach ((array) $query->arguments() as $key => $val) {
    $quoted[$key] = $connection->quote($val);
  }
  $sql = strtr($sql, $quoted);

  if ($config->get('db') == 'external') {
    // DB prefix.
    $dw_prefix = denormalizer_source_db();
    $search = ['{', '}'];
    $replace = [$dw_prefix . '.' . $connection->tablePrefix(), ''];
    $sql = str_replace($search, $replace, $sql);
  }
  else {
    $sql = $connection->prefixTables($sql);
  }

  return $sql;
}

/**
 * Get the current (source) database name.
 *
 * @return string
 *   Query result.
 */
function denormalizer_source_db() {
  // TODO: Drupal Rector Notice: Please delete the following comment after.
  // You've made any necessary changes.
  // You will need to use `\Drupal\core\Database\Database::getConnection()`.
  // If you do not yet have access to the container here.
  $db = \Drupal::database()->query('select database()')->fetchField();
  return $db;
}

/**
 * Get the target database name.
 *
 * @return string
 *   Database name.
 */
function denormalizer_target_db() {
  // TODO: Drupal Rector Notice: Please delete the following comment after.
  // You've made any necessary changes.
  // You will need to use `\Drupal\core\Database\Database::getConnection()`.
  // If you do not yet have access to the container here.
  $db = \Drupal::database()->query('select database()')->fetchField();
  $config = \Drupal::config('denormalizer.settings');
  return $config->get('db_prefix') . $db;
}

/**
 * Implements hook_hook_info().
 */
function denormalizer_hook_info() {
  $hooks = [];
  $hooks['denormalizer_alter'] = [
    'group' => 'denormalizer',
  ];
  $hooks['denormalizer_info'] = [
    'group' => 'denormalizer',
  ];
  return $hooks;
}

/**
 * Implements hook_denormalizer_alter().
 *
 * Add some default denormalization alters.
 *
 * @throws \Exception
 */
function denormalizer_denormalizer_alter(Select $q, $view, array $dn) {
  if ($view == 'user') {
    $q->addJoin('LEFT', 'users_roles', 'ur', 'ur.uid = dn_user.uid');
    $q->addJoin('LEFT', 'role', 'r', 'r.rid = ur.rid');
    $q->addExpression("group_concat(r.name SEPARATOR '|')", 'roles');
    // Group by primary key, so group_concat will work.
    $q->groupBy('dn_user.uid');
  }

  if ($view == 'webform_submissions') {
    $fields = &$q->getFields();
    // Remove the integer fields and replace them with dates.
    unset($fields['submitted']);
    $q->addExpression('from_unixtime(submitted)', 'submitted');
    unset($fields['completed']);
    $q->addExpression('from_unixtime(completed)', 'completed');
    unset($fields['modified']);
    $q->addExpression('from_unixtime(modified)', 'modified');
  }

  // @todo: move webform_component_bi into dw db
  if ($view == 'webform_component') {
    // Remove the name field and replace it with a varchar.
    $fields = &$q->getFields();
    unset($fields['name']);
    unset($fields['weight']);
    $q->addExpression('substr(name, 1, 255)', 'name');
    unset($fields['extra']);
    $q->addExpression('cast(weight as decimal(8,2))', 'weight');
    // Create surrogate key.
    $q->addExpression("CONCAT_WS('-', nid, dn_webform_component.form_key)", 'pk');

    // Extract grid components into their own form components.
    // TODO: Drupal Rector Notice: Please delete the following comment after.
    // You've made any necessary changes.
    // You will need to use `\Drupal\core\Database\Database::getConnection()`.
    // If you do not yet have access to the container here.
    $result = \Drupal::database()
      ->query("select nid, cid, form_key, extra, weight from {webform_component} where type='grid'");

    // Make a fake empty webform component table.
    $start = microtime(TRUE);
    $tablename = 'webform_component_bi';
    if (db_table_exists($tablename)) {
      db_drop_table($tablename);
    }
    // TODO: Drupal Rector Notice: Please delete the following comment after.
    // You've made any necessary changes.
    // You will need to use `\Drupal\core\Database\Database::getConnection()`.
    // If you do not yet have access to the container here.
    \Drupal::database()->query("create table {{$tablename}} select
      nid,
      cid,
      pid,
      cast(form_key as char(255)) as form_key,
      type,
      '' as value,
      required,
      cast('' as char(255)) as name,
      cast(weight as decimal(8,2)) as weight,
      cast('' as char(255)) as pk
      from {webform_component}
      limit 0");

    $batchValues = [];
    while ($row = $result->fetch()) {
      $data = unserialize($row->extra);
      if (isset($data['questions'])) {
        $questions = list_extract_allowed_values($data['questions'], 'list_text', FALSE);
        $i = 0;
        foreach ($questions as $key => $question) {
          $i++;
          $form_key = $row->form_key . '-' . $key;
          $batchValues[] = [
            'nid' => $row->nid,
            'cid' => $row->cid,
            'pid' => $row->cid,
            'form_key' => $form_key,
            'name' => substr($question, 0, 255),
            'type' => 'grid_sub',
            'weight' => $row->weight + ($i / 100),
            'pk' => $row->nid . '-' . $form_key,
          ];
        }
      }
    }
    foreach (array_chunk($batchValues, variable_get('denormalizer_chunk_size', 5000)) as $chunk) {
      // TODO: Drupal Rector Notice: Please delete the following comment after.
      // You've made any necessary changes.
      // You will need to use `\Drupal\core\Database\Database::getConnection()`.
      // If you do not yet have access to the container here.
      $insert = \Drupal::database()->insert($tablename)->fields([
        'nid',
        'cid',
        'pid',
        'form_key',
        'name',
        'type',
        'weight',
        'pk',
      ]);
      foreach ($chunk as $set) {
        $insert->values($set);
      }
      $insert->execute();
    }

    $end = microtime(TRUE);
    \Drupal::messenger()
      ->addStatus("Created intermediate TABLE $tablename with @c records in @s seconds.", [
        '@c' => count($batchValues),
        '@s' => round($end - $start, 2),
      ]);

    // TODO: Drupal Rector Notice: Please delete the following comment after.
    // You've made any necessary changes.
    // You will need to use `\Drupal\core\Database\Database::getConnection()`.
    // If you do not yet have access to the container here.
    $gridcomponents = \Drupal::database()
      ->select($tablename, 'dn_webform_component')
      ->fields('dn_webform_component');
    // We need to mirror the incremental conditions to this union subquery.
    $conditions = $q->havingConditions();
    foreach (element_children($conditions) as $key) {
      $gridcomponents->havingCondition($conditions[$key]['field'], $conditions[$key]['value'], $conditions[$key]['operator']);
    }
    $q->union($gridcomponents, 'ALL');
  }

  // @todo: move webform_component_av into dw db
  if ($view == 'webform_submitted_data') {
    // Remove the data field and replace it with a varchar.
    $fields = &$q->getFields();
    unset($fields['data']);
    $q->addExpression('substr(data, 1, 255)', 'data');

    // Create surrogate key.
    $q->addExpression("CONCAT_WS('-', sid, dn_webform_submitted_data.cid, no)", 'pk');

    // Dump unserialized data into a temporary table.
    $start = microtime(TRUE);

    $tablename = 'webform_component_av';
    if (db_table_exists($tablename)) {
      db_drop_table($tablename);
    }
    // TODO: Drupal Rector Notice: Please delete the following comment after.
    // You've made any necessary changes.
    // You will need to use `\Drupal\core\Database\Database::getConnection()`.
    // If you do not yet have access to the container here.
    \Drupal::database()
      ->query("create table {{$tablename}} select nid, cid, cast('' as char(255)) as `key`, cast('' as char(255)) as `value` from {webform_component} limit 0");

    db_add_primary_key($tablename, ['nid', 'cid', 'key']);
    // TODO: Drupal Rector Notice: Please delete the following comment after.
    // You've made any necessary changes.
    // You will need to use `\Drupal\core\Database\Database::getConnection()`.
    // If you do not yet have access to the container here.
    $result = \Drupal::database()
      ->query("select nid, cid, extra from {webform_component} where type in ('grid', 'select')");
    $batchValues = [];
    while ($row = $result->fetch()) {
      $data = unserialize($row->extra);
      $items = list_extract_allowed_values(isset($data['items']) ? $data['items'] : $data['options'], 'list_text', FALSE);
      foreach ($items as $key => $value) {
        $batchValues[] = [
          'nid' => $row->nid,
          'cid' => $row->cid,
          '`key`' => $key,
          'value' => substr($value, 0, 255),
        ];
      }
    }
    foreach (array_chunk($batchValues, variable_get('denormalizer_chunk_size', 5000)) as $chunk) {
      // TODO: Drupal Rector Notice: Please delete the following comment after.
      // You've made any necessary changes.
      // You will need to use `\Drupal\core\Database\Database::getConnection()`.
      // If you do not yet have access to the container here.
      $insert = \Drupal::database()->insert($tablename)->fields([
        'nid',
        'cid',
        '`key`',
        'value',
      ]);
      foreach ($chunk as $set) {
        $insert->values($set);
      }
      $insert->execute();
    }
    $end = microtime(TRUE);
    \Drupal::messenger()
      ->addStatus("Created intermediate TABLE $tablename with @c records in @s seconds.", [
        '@c' => count($batchValues),
        '@s' => round($end - $start, 2),
      ]);

    // Join the "webform allowed values" table.
    $q->addJoin('LEFT', $tablename, 'wav', 'dn_webform_submitted_data.data = wav.key and dn_webform_submitted_data.cid = wav.cid and  dn_webform_submitted_data.nid = wav.nid');
    $q->fields('wav', ['value']);

    // We really need the form keys.
    $q->addJoin('LEFT', 'webform_component', 'wc', 'dn_webform_submitted_data.nid = wc.nid and dn_webform_submitted_data.cid = wc.cid');
    // $q->fields('wc', array('form_key'));
    $q->addExpression("IF(wc.type != 'grid', form_key, (CONCAT_WS('-', form_key, no)))", 'form_key');
  }
}

/**
 * Sanitize webform data.
 * @param array $webformData
 *   The webform submitted data.
 * @param array $columns
 *   The webform fields as columns.
 *
 * @return array $sanitized
 *   A new formatted data array.
 */
function denormalizer_webform_data_sanitize($webformData, $columns) {
  $sanitized = [];
  $sid = $webformData[0]->sid;
  $element = [];

  foreach ($webformData as $index => $column) {
    if ($sid == $column->sid) {
      foreach ($columns as $col) {
        if (!isset($element['webform_id'])) {
          $element['webform_id'] = $column->webform_id;
          $element['sid'] = $column->sid;
        }

        if ($column->name == $col) {
          $element[$col] = $column->value;
        }
        elseif ($column->name  . "_" . $column->value == $col) {
          $element[$col] = 1;
        }
      }
      if ($index == count($webformData) - 1) {
        array_push($sanitized, $element);
      }
    }
    else {
      $sid = $column->sid;
      array_push($sanitized, $element);
      $element = [];
      foreach ($columns as $col) {
        if (!isset($element['webform_id'])) {
          $element['webform_id'] = $column->webform_id;
          $element['sid'] = $column->sid;
        }

        if ($column->name == $col) {
          $element[$col] = $column->value;
        }
        elseif ($column->name  . "_" . $column->value == $col) {
          $element[$col] = 1;
        }
      }
    }
  }

  return $sanitized;
}

/**
 * Add types to the query columns.
 * @param array $elements
 *   The array of columns.
 *
 * @return array $elements
 *   A new formatted array..
 */
function denormalizer_webform_sql_columns($elements) {
  array_unshift($elements,'sid int unsigned');
  array_unshift($elements,'webform_id varchar(32)');
  foreach ($elements as $index => $element) {
    if ($index !== 0 && $index !== 1) {
      $element = $element . ' mediumtext';
      $elements[$index] = $element;
    }
  }

  return $elements;
}

/**
 * Get elements from the webform decoded object.
 * @param string $bundles
 *   The webform_id.
 *
 * @return array $columns
 *   The field elements to transform in columns.
 */
function denormalizer_webform_get_columns($bundles) {
  $webform = Webform::load($bundles);
  $elements = $webform->getElementsDecoded();
  $columns = [];
  $fieldTypes = [
    'processed_text',
    'checkbox',
    'select',
    'term_select',
    'textarea',
    'webform_computed_twig',
    'webform_likert',
    'webform_term_select',
    'text\/css',
  ];
  $columns = denormalizer_webform_explore_elements($elements, $columns, $fieldTypes);

  return $columns;
}

/**
 * A recursive function to look for elements name.
 * @param array $elements
 *   The object to explore.
 * @param array $columns
 *   The columns to build.
 * @param array $fieldTypes
 *   The fields to take in count.
 *
 * @return array $columns
 *   The field elements to transform in columns.
 */
function denormalizer_webform_explore_elements($elements,$columns,$fieldTypes) {
  foreach ($elements as $key => $element) {
    if (is_array($element)) {
      if (isset($element['#type']) && in_array($element['#type'], $fieldTypes)) {
        array_push($columns, $key);
      }
      elseif (isset($element['#type']) && in_array($element['#type'], ['webform_likert', 'checkboxes'])) {
        foreach ($element['#options'] as $optionKey => $optionValue) {
          array_push($columns, $key . '_' . $optionKey);
        }
      }
      elseif (isset($element['#type'])) {
        $result = denormalizer_webform_explore_elements($element,$columns, $fieldTypes);
        if (!empty($result)) {
          foreach ($result as $value) {
            if (!in_array($value,$columns)) {
              array_push($columns, $value);
            }
          }
        }
      }
    }
  }

  return $columns;
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc