Unverified Commit 288a643c authored by Stefan Auditor's avatar Stefan Auditor Committed by Stefan Auditor
Browse files

Issue #3282696 by sanduhrs: Port of l10n_community: Add statistics service

parent 36ee0c58
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
services:
  l10n_community.statistics:
    class: Drupal\l10n_community\L10nStatistics
    arguments: ['@database']
+153 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\l10n_community;

use Drupal\Core\Database\Connection;
use Drupal\l10n_server\Entity\L10nServerProjectInterface;

/**
 * Service description.
 *
 * @todo
 *   These queries are *slooow*. The query cache helps a lot with caching the
 *   result, so the slowness only shows for the first run, but still it would be
 *   good to look into optimizing these.
 */
class L10nStatistics {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $connection;

  /**
   * Constructs a L10nStatistics object.
   *
   * @param \Drupal\Core\Database\Connection $connection
   *   The database connection.
   */
  public function __construct(Connection $connection) {
    $this->connection = $connection;
  }

  /**
   * Get count of all strings.
   */
  public function getStringCount(): int {
    return $this->connection
      ->query("SELECT COUNT(sid) FROM {l10n_server_string}")
      ->fetchField();
  }

  /**
   * Get count of all strings in this project.
   *
   * @param \Drupal\l10n_server\Entity\L10nServerProjectInterface $project
   *   A l10n_server_project entity.
   */
  public function getProjectStringCount(L10nServerProjectInterface $project): int {
    $query = $this->connection
      ->query('SELECT COUNT(DISTINCT l.sid) FROM {l10n_server_line} l WHERE l.pid = :pid', [':pid' => $project->id()]);
    return $query->fetchField();
  }

  /**
   * Get count of all warnings in this project.
   *
   * @param \Drupal\l10n_server\Entity\L10nServerProjectInterface $project
   *   A l10n_server_project entity.
   */
  public function getProjectWarningsCount(L10nServerProjectInterface $project): int {
    $query = $this->connection
      ->query('SELECT COUNT(DISTINCT e.eid) FROM {l10n_server_project} p LEFT JOIN {l10n_server_release} r ON p.pid = r.pid LEFT JOIN {l10n_server_error} e ON r.rid = e.rid WHERE p.uri = :uri', [':uri' => $project->getUri()]);
    return $query->fetchField();
  }

  /**
   * Get summaries based on language codes.
   *
   * @param L10nServerProjectInterface|null $project
   *   A l10n_server_project entity.
   *
   * @return array
   */
  public function getLanguagesStringCount(L10nServerProjectInterface $project = NULL): array {
    $sums = [];
    if (!isset($l10n_project_id)) {
      // Simple count query if we are not filtering by project.
      $count1_sql = "SELECT COUNT(sid) AS translation_count, language FROM {l10n_server_status_flag} WHERE has_translation = 1 GROUP BY language";
      $count2_sql = "SELECT COUNT(sid) AS translation_count, language FROM {l10n_server_status_flag} WHERE has_suggestion = 1 GROUP BY language";
      $count_args = [];
    }
    else {
      // More complex joins if we also need to factor the project in.
      $count1_sql = "SELECT COUNT(DISTINCT ts.sid) AS translation_count, ts.language FROM {l10n_server_line} l INNER JOIN {l10n_server_status_flag} ts ON l.sid = ts.sid WHERE l.pid = :pid AND ts.has_translation = 1 GROUP BY ts.language";
      $count2_sql = "SELECT COUNT(DISTINCT ts.sid) AS translation_count, ts.language FROM {l10n_server_line} l INNER JOIN {l10n_server_status_flag} ts ON l.sid = ts.sid WHERE l.pid = :pid AND ts.has_suggestion = 1 GROUP BY ts.language";
      $count_args = array(':pid' => $project->id());
    }
    $result = $this->connection->query($count1_sql, $count_args);
    foreach ($result as $row) {
      $sums[$row->language]['translations'] = $row->translation_count;
    }
    $result = $this->connection->query($count2_sql, $count_args);
    foreach ($result as $row) {
      $sums[$row->language]['suggestions'] = $row->translation_count;
    }
    return $sums;
  }

  /**
   * Get summaries by projects.
   *
   * @param string $langcode
   *   A langcode string, e.g. 'en', 'fr' or 'de'.
   */
  public function getProjectsStringCount(string $langcode): array {
    // First get the count of strings available for translation.
    $sums = [];
    $result = $this->connection
      ->query("SELECT COUNT(DISTINCT sid) AS string_count, pid FROM {l10n_server_line} GROUP BY pid");
    foreach ($result as $row) {
      $sums[$row->pid] = ['count' => $row->string_count];
    }
    // Get the count of distinct strings having translations and suggestions per
    // project. This is run per project because big installs of the module were
    // choking on GROUP BY based solutions.
    foreach (['translations' => 'has_translation', 'suggestions' => 'has_suggestion'] as $key => $column) {
      foreach ($sums as $pid => &$data) {
        $count_args = [];
        $count_sql = "SELECT COUNT(DISTINCT ts.sid) AS translation_count FROM {l10n_server_line} l LEFT JOIN {l10n_server_status_flag} ts ON l.sid = ts.sid WHERE ts.$column = 1 ";
        if (isset($id)) {
          // Limit to language if desired.
          $count_sql .= "AND ts.language = :language ";
          $count_args[':language'] = $langcode;
        }
        $count_sql .= 'AND l.pid = :pid';
        $count_args[':pid'] = $pid;
        $data[$key] = $this->connection->query($count_sql, $count_args)->fetchField();
      }
    }
    return $sums;
  }

  /**
   * Get summaries of people having most active translations per language.
   *
   * Skip anonymous since that is used for placeholders when there was no prior
   * translations for a suggestion.
   *
   * @param string $langcode
   *   A langcode string, e.g. 'en', 'fr' or 'de'.
   */
  public function getPeopleStringCount(string $langcode): array {
    // Get summaries of people having most active translations per language.
    // Skip anonymous since that is used for placeholders when there was no
    // prior translations for a suggestion.
    $result = $this->connection
      ->queryRange("SELECT COUNT(DISTINCT t.sid) AS sum, u.name, u.uid FROM {l10n_server_translation} t LEFT JOIN {users_field_data} u ON t.uid = u.uid WHERE t.status = 1 AND t.suggestion = 0 AND t.language = :lng AND u.uid != 0 GROUP BY t.uid ORDER BY sum DESC", 0, 10, [':lng' => $langcode]);
    return $result->fetchAll();
  }

}