You are here

function lingotek_grid_get_rows in Lingotek Translation 7.5

Same name and namespace in other branches
  1. 7.7 lingotek.bulk_grid.inc \lingotek_grid_get_rows()
  2. 7.4 lingotek.bulk_grid.inc \lingotek_grid_get_rows()
  3. 7.6 lingotek.bulk_grid.inc \lingotek_grid_get_rows()

Dynamic query processing function for the grid Since the header defines which columns are shown, this query gets all possible values and refines the header using the columns selected in the UI The filters are also processed here

Return value

array $table_data Returns array of rows Populates The Grid

1 call to lingotek_grid_get_rows()
lingotek_bulk_grid_form in ./lingotek.bulk_grid.inc

File

./lingotek.bulk_grid.inc, line 980
Bulk Grid form

Code

function lingotek_grid_get_rows($entity_type, $form, &$form_state, $count_only = FALSE) {
  $info = entity_get_info($entity_type);
  $entity_id_key = $info['entity keys']['id'];
  $eid = 'n.' . $entity_id_key;
  $base_table = $info['base table'];
  $entity_properties = array_flip($info['schema_fields_sql']['base table']);
  $label_col = isset($info['entity keys']['label']) && $info['entity keys']['label'] ? $info['entity keys']['label'] : NULL;
  $bundle_col = isset($info['entity keys']['bundle']) && $info['entity keys']['bundle'] && isset($entity_properties[$info['entity keys']['bundle']]) ? $info['entity keys']['bundle'] : NULL;

  // All managed entity types should have a language column.
  // Field collection entities have one, but it is called 'langcode'.
  // Message type entities have one, and it is called 'language'; but currently it does not appear in their entity keys.
  // So, the $language_col looks for the correct language field, and then guesses it is 'language' if it doesn't find one.
  $language_col = isset($info['entity keys']['language']) && $info['entity keys']['language'] ? $info['entity keys']['language'] : 'language';
  $table_data = array();
  $limit = isset($_SESSION['limit_select']) ? $_SESSION['limit_select'] : 10;
  $columns = isset($form_state['values']['columns']) ? $form_state['values']['columns'] : array();
  $source = isset($form_state['values']['source']) ? $form_state['values']['source'] : TRUE;
  $header = array(
    // Define the tentative source header
    'nid' => array(
      'data' => t('ID'),
      'field' => 'n.' . $entity_id_key,
    ),
    'content_type' => array(
      'data' => t('Content Type'),
      'field' => 'type',
    ),
    'title' => array(
      'data' => t('Title'),
      'field' => 'n.' . $label_col,
    ),
    'language' => array(
      'data' => t('Source Uploaded'),
    ),
    //, 'field' => 'upload_status'),
    'translations' => array(
      'data' => t('Translations'),
      'field' => 't_current_c',
    ),
    'configuration' => array(
      'data' => t('Profile'),
    ),
    'workflow' => array(
      'data' => t('Workflow'),
      'field' => 'workflow',
    ),
    'document_id' => array(
      'data' => t('Doc ID'),
      'field' => 'document_id',
    ),
    'changed' => array(
      'data' => t('Last Modified'),
      'field' => 'changed',
    ),
    'last_uploaded' => array(
      'data' => t('Last Uploaded'),
      'field' => 'last_uploaded',
    ),
    'actions' => array(
      'data' => t('Actions'),
    ),
    'translation_status' => array(
      'data' => t('Translation Status'),
    ),
    'last_downloaded' => array(
      'data' => t('Last Downloaded'),
      'field' => 'last_downloaded',
    ),
    'translate_link' => array(
      'data' => t('Translate'),
    ),
  );
  if (!isset($entity_properties['changed'])) {
    unset($header['changed']);
  }
  if (!$label_col) {
    unset($header['title']);
  }

  // Taxonomy terms require special handling of bundles because they do not
  // have a bundle column in their table.
  if (!$bundle_col && $entity_type != 'taxonomy_term') {
    unset($header['content_type']);
  }
  if (isset($entity_properties['changed'])) {
    $header['changed']['sort'] = 'desc';
  }
  foreach ($header as $title => $data) {

    // Refine the source header using the selected columns
    if (array_key_exists($title, $columns) && $columns[$title]) {
      $form_state['values']['grid_header'][$title] = $data;
    }
  }

  // Initialize Query and extend paginator and tablesort if necessary
  if ($count_only) {
    $query = db_select('{' . $base_table . '}', 'n');
  }
  else {
    $query = db_select('{' . $base_table . '}', 'n')
      ->extend('PagerDefault')
      ->extend('TableSort');
    $query
      ->limit($limit)
      ->orderByHeader($form_state['values']['grid_header']);
  }
  if ($base_table == 'node') {
    $query
      ->innerJoin('{node}', 'node2', '(n.nid = node2.nid) AND (node2.tnid = 0 OR node2.tnid = node2.nid)');
  }

  // Entity Title and Name of Content Type (type)
  $query
    ->fields('n', array(
    $entity_id_key,
  ));
  if ($label_col) {
    $query
      ->addField('n', $label_col, 'title');
  }
  if ($language_col) {
    $query
      ->addField('n', $language_col, 'language');
  }
  if (isset($entity_properties['changed'])) {
    $query
      ->addField('n', 'changed');
  }
  if ($entity_type == 'comment') {
    $query
      ->leftJoin('{node}', 'nn', 'nn.nid = n.nid');
    $query
      ->addExpression("CONCAT('comment_node_',nn.type)", 'type');
    $query
      ->addExpression("CONCAT('comment_node_',nn.type)", 'node_type');
  }
  elseif ($entity_type == 'taxonomy_term') {
    $query
      ->innerJoin('{taxonomy_vocabulary}', 'tv', 'n.vid = tv.vid');
    $query
      ->addField('tv', 'name', 'tv_name');
    $query
      ->addField('tv', 'machine_name', 'type');
  }
  elseif ($bundle_col) {
    if ($info['entity keys']['bundle'] != 'type') {
      $query
        ->addField('n', $info['entity keys']['bundle']);
    }
    $query
      ->addField('n', $info['entity keys']['bundle'], 'type');
  }
  $query
    ->addExpression("(SELECT COUNT(entity_id) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='CURRENT')", 't_current_c');
  $query
    ->addExpression("(SELECT GROUP_CONCAT(SUBSTRING(entity_key, 20, 10)) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='PENDING')", 't_pending');
  $query
    ->addExpression("(SELECT GROUP_CONCAT(SUBSTRING(entity_key, 20, 10)) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='READY')", 't_ready');
  $query
    ->addExpression("(SELECT GROUP_CONCAT(SUBSTRING(entity_key, 20, 10)) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='CURRENT')", 't_current');
  $query
    ->addExpression("(SELECT GROUP_CONCAT(SUBSTRING(entity_key, 20, 10)) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='EDITED')", 't_edited');
  $query
    ->addExpression("(SELECT GROUP_CONCAT(SUBSTRING(entity_key, 20, 10)) FROM {lingotek_entity_metadata} WHERE entity_type='" . $entity_type . "' AND entity_id=" . $eid . " AND entity_key LIKE 'target_sync_status_%' AND value='UNTRACKED')", 't_untracked');
  $filters = isset($_SESSION['grid_filters']) ? $_SESSION['grid_filters'] : array();
  global $language;
  $localized_label_table = 'field_data_' . $label_col . '_field';
  if ($label_col && db_table_exists($localized_label_table)) {
    $query
      ->leftJoin('{' . $localized_label_table . '}', 't_title', 't_title.entity_id = ' . $eid . ' and t_title.entity_type = \'' . $entity_type . '\' and t_title.language=\'' . $language->language . '\'');
    $query
      ->addField('t_title', $label_col . '_field_value', 'localized_title');
  }

  // left joins are necessary here because some lingotek table keys might not exist
  // Lingotek Document ID
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_document_id', 'lingo_document_id.entity_type =\'' . $entity_type . '\' AND lingo_document_id.entity_id = ' . $eid . ' and lingo_document_id.entity_key = \'document_id\'');
  $query
    ->addField('lingo_document_id', 'value', 'document_id');

  // Entity Upload Status
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_upload_status', 'lingo_upload_status.entity_type =\'' . $entity_type . '\' AND lingo_upload_status.entity_id = ' . $eid . ' and lingo_upload_status.entity_key = \'node_sync_status\' and lingo_upload_status.value <> \'' . LingotekSync::STATUS_TARGET . '\'');

  //$query->leftJoin('{lingotek_entity_metadata}', 'lingo_upload_status', 'lingo_upload_status.nid = ' . $eid . ' and lingo_upload_status.entity_key = \'node_sync_status\'');

  //$query->condition('lingo_upload_status.value', LingotekSync::STATUS_TARGET, '<>');
  $query
    ->addField('lingo_upload_status', 'value', 'upload_status');

  // Profile Settings
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_profile', 'lingo_profile.entity_type =\'' . $entity_type . '\' AND lingo_profile.entity_id = ' . $eid . ' and lingo_profile.entity_key = \'profile\'');
  $query
    ->addField('lingo_profile', 'value', 'profile');

  // Last Uploaded Timestamp
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_last_uploaded', 'lingo_last_uploaded.entity_type =\'' . $entity_type . '\' AND lingo_last_uploaded.entity_id = ' . $eid . ' and lingo_last_uploaded.entity_key = \'last_uploaded\'');
  $query
    ->addField('lingo_last_uploaded', 'value', 'last_uploaded');

  // Any Upload Errors
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_last_sync_error', 'lingo_last_sync_error.entity_type =\'' . $entity_type . '\' AND lingo_last_sync_error.entity_id = ' . $eid . ' and lingo_last_sync_error.entity_key = \'last_sync_error\'');
  $query
    ->addField('lingo_last_sync_error', 'value', 'last_sync_error');
  $query
    ->leftJoin('{lingotek_entity_metadata}', 'lingo_workflow', '' . $eid . ' = lingo_workflow.entity_id and lingo_workflow.entity_type =\'' . $entity_type . '\' and lingo_workflow.entity_key = \'workflow_id\'');
  $query
    ->addField('lingo_workflow', 'value', 'workflow');
  if (isset($filters['search_type']) && $filters['search_type'] == 'all') {
    $filters['title'] = $filters['body'] = $filters['search'];
  }
  if (isset($filters['title'])) {
    $title_query = db_select('{field_data_title_field}', 'tf')
      ->distinct()
      ->fields('tf', array(
      'entity_id',
    ))
      ->condition('tf.title_field_value', '%' . $filters['title'] . '%', 'LIKE');
  }
  if (isset($filters['body'])) {
    $body_query = db_select('{field_data_body}', 'tb')
      ->distinct()
      ->fields('tb', array(
      'entity_id',
    ))
      ->condition('tb.body_value', '%' . $filters['body'] . '%', 'LIKE');
  }

  // START FILTERS
  //  Search
  if (isset($filters['search_type']) && $filters['search_type'] == 'all' && isset($filters['search']) && strlen($filters['search'])) {
    $or = db_or();
    if (!empty($label_col)) {
      $or
        ->condition('n.' . $label_col, '%' . $filters['search'] . '%', 'LIKE');

      // is this redundant when the  following line is added?
    }
    $or
      ->condition('' . $eid . '', $title_query, 'IN');
    $or
      ->condition('' . $eid . '', $body_query, 'IN');
    $query
      ->condition($or);
  }
  else {

    //  Title Field
    if (isset($filters['title']) && $filters['title'] != '') {
      $query
        ->condition('' . $eid . '', $title_query, 'IN');
    }

    // Body Field
    if (isset($filters['body']) && $filters['body'] != '') {
      $query
        ->condition('' . $eid . '', $body_query, 'IN');
    }
  }

  //  Entity ID
  if (isset($filters['nid']) && $filters['nid'] != '') {
    $query
      ->condition('' . $eid . '', $filters['nid']);
  }

  // Lingotek Document ID
  if (isset($filters['document_id']) && $filters['document_id'] != '') {
    if ($filters['document_id'] == 'None') {
      $query
        ->condition('lingo_document_id.value', NULL);
    }
    else {
      $query
        ->condition('lingo_document_id.value', $filters['document_id']);
    }
  }
  $array_fix = array(
    'upload_status',
    'content_type',
    'auto_upload',
    'auto_download',
    'crowdsourcing',
    'url_alias',
    'translation_status',
    'locale_progress_percent',
  );
  foreach ($array_fix as $value) {
    if (isset($filters[$value]) && !is_array($filters[$value])) {
      $filters[$value] = array(
        $filters[$value],
      );
    }
  }

  // Source Language
  if (isset($filters['source_language']) && $filters['source_language'] != 'all') {
    $query
      ->condition('n.' . $info['entity keys']['language'], $filters['source_language']);
  }

  // Upload Status
  if (isset($filters['upload_status']) && !in_array('all', $filters['upload_status'])) {
    $query
      ->condition('lingo_upload_status.value', $filters['upload_status'], 'IN');
  }

  //  Content Type
  if (isset($filters['content_type']) && !in_array('all', $filters['content_type'])) {

    // Special-case handling of taxonomy_term pseudo-entities
    if ($entity_type == 'taxonomy_term') {
      $query
        ->condition('tv.machine_name', $filters['content_type'], 'IN');
    }
    else {
      $query
        ->condition('n.' . $info['entity keys']['bundle'], $filters['content_type'], 'IN');
    }
  }
  if (isset($filters['profile']) && !in_array('all', $filters['profile'])) {
    $profiled_entities = lingotek_get_entities_by_profile_and_entity_type($filters['profile'], $entity_type);
    $profiled_entity_ids = array(
      -1,
    );
    foreach ($profiled_entities as $p) {
      $profiled_entity_ids[] = $p['id'];
    }
    $query
      ->condition('n.' . $info['entity keys']['id'], $profiled_entity_ids, 'IN');

    //$or = lingotek_profile_condition($base_table, 'n', 'lingo_profile', $filters['profile']);

    //$query->condition($or);
  }

  // Last Uploaded
  if (isset($filters['last_uploaded']) && $filters['last_uploaded'] != 'all') {
    if ($filters['last_uploaded'] == '1 day') {
      $query
        ->condition('lingo_last_uploaded.value', strToTime($filters['last_uploaded']), '<');
    }
    elseif ($filters['last_uploaded'] == 'unknown') {
      $query
        ->condition('lingo_last_uploaded.value', NULL);
    }
    else {
      $params = explode(' ', $filters['last_uploaded'], 2);

      // string formatted like '< 1 week', so explode with a limit of two gives us array(0 => '<', 1 => '1 week')
      $query
        ->condition('lingo_last_uploaded.value', strToTime($params[1]), $params[0]);
    }
  }

  // Last Downloaded
  if (isset($filters['last_downloaded']) && $filters['last_downloaded'] != 'all') {
    if ($filters['last_downloaded'] == '1 day') {
      $query
        ->condition('lingo_last_downloaded.value', strToTime($filters['last_downloaded']), '<');
    }
    elseif ($filters['last_downloaded'] == 'unknown') {
      $query
        ->condition('lingo_last_downloaded.value', NULL);
    }
    else {
      $params = explode(' ', $filters['last_downloaded'], 2);

      // string formatted like '< 1 week', so explode with a limit of two gives us array(0 => '<', 1 => '1 week')
      $query
        ->condition('lingo_last_downloaded.value', strToTime($params[1]), $params[0]);
    }
  }

  // END FILTERS
  // If count only, return the count
  if ($count_only) {
    $result = $query
      ->execute();
    return $result
      ->rowCount();
  }

  // Execute the query
  $table_data_raw = $query
    ->execute()
    ->fetchAllAssoc($entity_id_key);
  lingotek_entity_load($table_data_raw, $entity_type);
  $languages = language_list();
  $profiles = lingotek_get_profiles();
  $api = LingotekApi::instance();
  $workflows = $api
    ->listWorkflows();
  $types = _node_types_build()->types;

  // Parse returned objects and make them arrays keyed by the Node ID for clean use in The Grid.
  foreach ($table_data_raw as $row) {
    $entity_id = $row->{$entity_id_key};

    // RENAMING
    $title_truncate_length = 55;
    if (strlen($row->title) > $title_truncate_length) {

      // very long title names make The Grid look messy, so we truncate them.
      $dots = '...';
      $dots_length = strlen($dots);
      $row->title = substr($row->title, 0, $title_truncate_length - $dots_length) . $dots;
    }
    $icon = '';
    if ($row->lingotek['profile'] == LingotekSync::PROFILE_DISABLED) {
      $icon = '<i class="fa fa-minus-square" style="color: #999;" title="' . t('Lingotek is disabled') . '"></i>';
    }
    elseif (!is_null($row->upload_status)) {
      switch ($row->upload_status) {
        case LingotekSync::STATUS_EDITED:
          $icon = '<i class="fa fa-square-o" title="' . t('Needs to be uploaded') . '"></i>';
          break;
        case LingotekSync::STATUS_CURRENT:
          $icon = '<i class="fa fa-check-square" title="' . t('Uploaded to Lingotek') . '"></i>';
          break;
        case LingotekSync::STATUS_PENDING:
          $icon = '<i class="fa fa-square" title="' . t('Upload to Lingotek in progress') . '"></i>';
          break;
        case LingotekSync::STATUS_FAILED:
          $error = $row->last_sync_error ? $row->last_sync_error : '';
          $icon = '<i class="fa fa-warning" style="color: darkorange;" title="' . t('Lingotek processing failed @error', array(
            '@error' => ': ' . $error,
          )) . '"></i>';
          break;
        default:
          $icon = '<i class="fa fa-question-circle" style="color: darkorange;" title="' . t('Unknown upload status') . ': ' . check_plain($row->upload_status) . '"></i>';
          break;
      }
    }
    else {
      $icon = '<i class="fa fa-square-o" title="' . t('Needs to be uploaded') . '"></i>';
    }
    $list_statuses = array(
      'pending',
      'ready',
      'current',
      'edited',
      'untracked',
    );
    $locales = array();
    $statuses = array();
    foreach ($list_statuses as $status) {
      $key = 't_' . $status;
      foreach (explode(',', $row->{$key}) as $l) {
        if (!empty($l)) {
          $locales[] = $l;
          $statuses[] = $status;
        }
      }
    }
    array_multisort($locales, SORT_ASC, $statuses);
    $disabled = $row->lingotek['profile'] == LingotekSync::PROFILE_DISABLED;
    $translations = lingotek_lang_icons($entity_type, $languages, $locales, $statuses, $entity_id, $disabled, $row->language);

    // show translation statuses
    $configuration = '';
    $disabled_class = $disabled ? ' ltk-disabled-icon' : '';
    if ($row->lingotek['create_lingotek_document']) {
      $configuration .= '<i class="fa fa-arrow-up' . $disabled_class . '" title="' . t('Automatic Upload') . '"></i> ';
    }
    if ($row->lingotek['sync_method']) {
      $configuration .= '<i class="fa fa-arrow-down' . $disabled_class . '" title="' . t('Automatic Download') . '"></i> ';
    }
    if ($row->lingotek['allow_community_translation']) {
      $configuration .= '<i class="fa fa-globe' . $disabled_class . '" title="' . t('Crowdsourcing Enabled') . '"></i> ';
    }
    if ($row->lingotek['profile'] == LingotekSync::PROFILE_CUSTOM) {
      $configuration = t('Custom') . ' <span class="node-configuration">' . $configuration . '</span>';
    }
    elseif ($row->lingotek['profile'] == LingotekSync::PROFILE_DISABLED) {
      $configuration = t('Disabled');
    }
    else {
      $profile_key = $row->lingotek['profile'];
      if (array_key_exists($profile_key, $profiles)) {
        $configuration = t($profiles[$profile_key]['name']);
      }
      else {
        $configuration = t('Unknown');

        // profile id does not exist in profiles (this state should be unobtainable)
      }
    }

    // Source
    $source = '<span class="lingotek-language-source" style="white-space: nowrap;">' . $icon . ' ';
    if ($language_col) {
      $source .= $row->language == LANGUAGE_NONE ? t('Language Neutral') : t($languages[$row->language]->name);
    }
    $source .= '</span>';
    $linked_statuses = array(
      LingotekSync::STATUS_EDITED,
      LingotekSync::STATUS_FAILED,
    );
    $needs_upload = (in_array($row->upload_status, $linked_statuses) || empty($row->upload_status)) && $row->lingotek['profile'] != LingotekSync::PROFILE_DISABLED;
    if ($needs_upload) {

      // add link for upload
      $source = '<span title="Upload Now" class="ltk-upload-button lingotek-language-source" onclick="lingotek_perform_action(' . $entity_id . ',\'upload\')">' . $source . '</span>';
    }
    $pm_icon = $entity_type == 'node' ? ' <i class="fa fa-tasks' . $disabled_class . '"></i>' : '';
    $pm_link = ' ' . l($pm_icon, 'node/' . $entity_id . '/lingotek_pm', array(
      'html' => TRUE,
      'attributes' => array(
        'title' => t('View Translations'),
        'target' => '_blank',
      ),
    ));
    $actions = '';
    $actions .= lingotek_get_entity_edit_link($entity_type, $entity_id);
    $actions .= empty($disabled_class) ? $pm_link : $pm_icon;
    $actions .= ' ' . l('<i title="' . t('Set Lingotek Settings') . '" class="fa fa-gear"></i>', '', array(
      'html' => TRUE,
      'attributes' => array(
        'onclick' => 'lingotek_perform_action(' . $entity_id . ',"edit"); return false;',
      ),
    ));
    $no_localized_title = language_default()->language != $language->language && (!isset($row->localized_title) or $row->localized_title == '');
    if ($label_col) {
      $uri = isset($info['uri callback']) ? call_user_func($info['uri callback'], $row) : '';
      $uri['options']['attributes'] = array(
        'target' => '_blank',
      );
      $title_to_show = isset($row->localized_title) ? $row->localized_title : $row->title;
      $title = $no_localized_title ? '<span class="no-localized-title">' : '';
      if (isset($uri['path'])) {
        $title .= l($title_to_show, $uri['path'], $uri['options']);
      }
      else {
        $title .= $title_to_show;
      }
      $title .= $no_localized_title ? '</span>' : '';
    }
    else {
      $title = '';
    }

    // Build the data to be output for this row
    $data = array(
      'nid' => $row->{$entity_id_key} ?: t('??'),
      'title' => $title,
      'language' => $source,
      'translations' => $translations,
      'configuration' => $configuration,
      'document_id' => $row->document_id ?: t('N/A'),
      'content_type' => isset($info['bundles'][$row->type]['label']) ? $info['bundles'][$row->type]['label'] : $row->type,
      'last_uploaded' => $row->last_uploaded ? t('@time ago', array(
        '@time' => lingotek_human_readable_timestamp($row->last_uploaded),
      )) : t('Never'),
      'workflow' => $row->lingotek['workflow_id'] ? isset($workflows[$row->lingotek['workflow_id']]) ? check_plain($workflows[$row->lingotek['workflow_id']]) : $row->lingotek['workflow_id'] : '',
      'actions' => '<span class="lingotek-node-actions">' . $actions . '</span>',
    );
    if (isset($entity_properties['changed'])) {
      $data['changed'] = $row->changed ? t('@time ago', array(
        '@time' => lingotek_human_readable_timestamp($row->changed),
      )) : t('Never');
    }
    $table_data[$entity_id] = $data;
  }
  return $table_data;
}