g2-8.x-1.x-dev/src/Controller/Initial.php

src/Controller/Initial.php
<?php

declare(strict_types=1);

namespace Drupal\g2\Controller;

use Drupal\Core\Database\Connection;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\g2\G2;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class Initial contains the controller for the items-by-initial page.
 *
 * @phpstan-consistent-constructor
 */
class Initial implements ContainerInjectionInterface {

  use StringTranslationTrait;

  /**
   * The current_user service.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

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

  /**
   * The entity_type.manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $etm;

  /**
   * Initial constructor.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The database service.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current_user service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $etm
   *   The entity_type.manager service.
   */
  public function __construct(
    Connection $database,
    AccountInterface $current_user,
    EntityTypeManagerInterface $etm,
  ) {
    $this->currentUser = $current_user;
    $this->database = $database;
    $this->etm = $etm;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    /** @var \Drupal\Core\Session\AccountInterface $current_user */
    $current_user = $container->get('current_user');
    /** @var \Drupal\Core\Database\Connection $database */
    $database = $container->get('database');
    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
    $etm = $container->get(G2::SVC_ETM);
    return new static($database, $current_user, $etm);
  }

  /**
   * Controller for route g2.initial.
   *
   * @param string $g2_initial
   *   The raw initial matching the route regexp.
   *
   * @return array<string,mixed>
   *   The render array.
   */
  public function indexAction($g2_initial): array {
    // Parameter g2_initial has been checked against route regex, so it is safe.
    $nodes = $this->getByInitial($g2_initial);
    return [
      '#theme' => 'g2_initial',
      '#entries' => $nodes,
      '#initial' => $g2_initial,
    ];
  }

  /**
   * Return a list of words starting with an initial segment.
   *
   * Segments are typically one letter, but can be any starting substring.
   *
   * The logic is different from the one in G2\entries() because we don't care
   * for the special case of "/" as an initial segment.
   *
   * XXX Abstract to EntityQuery.
   *
   * @param string $initial
   *   Usually a single letter. Assumed to be safe, so do not call this method
   *   on raw user input.
   *
   * @return array<string,mixed>
   *   A render array.
   */
  protected function getByInitial($initial): array {
    $ar_total = $this->getStats();
    $ar_initial = $this->getStats(0, $initial);

    $stats_basic = $this->t("<p>Displaying @count entries starting with '%initial' from a total number of @total entries.</p>",
      [
        // _g2_stats() does not return empty arrays, so no need to check values.
        '@count' => $ar_initial[NodeInterface::PUBLISHED],
        '%initial' => $initial,
        '@total' => $ar_total[NodeInterface::PUBLISHED],
      ]
    );

    if ($this->currentUser->hasPermission(G2::PERM_ADMIN)) {
      $stats_admin = $this->t('<p>Admin info: there are also @count unpublished matching entries from a total number of @total unpublished entries.</p>',
        [
          '@count' => $ar_initial[NodeInterface::NOT_PUBLISHED],
          '@total' => $ar_total[NodeInterface::NOT_PUBLISHED],
        ]
      );
    }
    else {
      $stats_admin = NULL;
    }

    unset($ar_initial);
    unset($ar_total);

    $query = $this->database->select(G2::TYPE, 'n');
    $query->innerJoin('node_field_revision', 'nfv', 'n.vid = nfv.vid');
    /** @var \Drupal\Core\Database\Query\SelectInterface $query */
    $query = $query->fields('n', ['nid'])
      ->orderBy('nfv.title')
      ->addTag('node_access');
    $query
      ->condition('n.type', G2::BUNDLE)
      ->condition('nfv.status', "1")
      ->condition('nfv.title', $initial . '%', 'LIKE');

    $node_ids = [];
    $result = $query->execute();
    if ($result instanceof StatementInterface) {
      foreach ($result as $row) {
        $node_ids[] = $row->nid;
      }
    }

    $nodes = $this->etm
      ->getStorage(G2::TYPE)
      ->loadMultiple($node_ids);
    if (empty($nodes)) {
      $result = [
        'entries' => ['#markup' => $this->t('No entry found for %initial.', ['%initial' => $initial])],
      ];
    }
    else {
      $builder = $this->etm->getViewBuilder(G2::TYPE);
      $result = [
        'stats-basic' => ['#markup' => $stats_basic],
        'entries' => $builder->viewMultiple($nodes, G2::VM_ENTRY_LIST),
      ];
    }

    $result['stats-admin'] = ['#markup' => $stats_admin];
    $result['entries']['#weight'] = 10;

    return $result;
  }

  /**
   * Title callback for route g2.initial.
   *
   * @param string $g2_initial
   *   The raw initial matching the route regexp.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The page title.
   */
  public function indexTitle($g2_initial = '@'): TranslatableMarkup {
    $result = $this->t('Entries starting with initial %initial', [
      '%initial' => $g2_initial,
    ]);

    return $result;
  }

  /**
   * Extract statistics from the G2 glossary.
   *
   * @param int $tid
   *   Taxonomy term id.
   * @param string $initial
   *   Initial segment.
   *
   * @return array<int,int>
   *   - 0: g2 entries having chosen taxonomy term
   *   - 1: g2 entries starting with chosen initial segment
   */
  protected function getStats(int $tid = 0, string $initial = ''): array {
    $sql = <<<SQL
SELECT
  COUNT(distinct n.nid) cnt, nfd.status
FROM {node} n
  INNER JOIN {node_field_revision} nfd ON n.vid = nfd.vid

SQL;

    $sq_params = [];
    $sq_test = "WHERE n.type = :node_type \n";

    $sq_params[':node_type'] = G2::BUNDLE;

    if ($tid > 0) {
      $sql .= "  INNER JOIN {taxonomy_index} tn ON n.nid = tn.nid \n";
      $sq_test .= "  AND tn.tid = :tid \n";
      $sq_params[':tid'] = $tid;
    }

    if (!empty($initial)) {
      $sq_test .= "  AND nfd.title LIKE :title \n";
      $sq_params[':title'] = $initial . '%';
    }
    $sql .= $sq_test . " GROUP BY nfd.status \n";

    $counts = $this->database->query($sql, $sq_params);
    assert($counts instanceof StatementInterface);

    // Avoid empty returns.
    $result = [
      NodeInterface::NOT_PUBLISHED => 0,
      NodeInterface::PUBLISHED => 0,
    ];

    foreach ($counts as $row) {
      $result[intval($row->status)] = intval($row->cnt);
    }

    return $result;
  }

  /**
   * Controller for the g2.initial.bare route.
   *
   * @param string $route_name
   *   The redirection target route.
   * @param array<string,mixed> $route_parameters
   *   The redirection target route parameters.
   * @param array<string,mixed> $options
   *   The redirection target route options.
   * @param int $status
   *   The redirect status to use.
   * @param int $max_age
   *   The max age for the redirect response.
   *
   * @return \Drupal\Core\Routing\TrustedRedirectResponse
   *   The redirect response.
   */
  public function redirect(
    string $route_name,
    array $route_parameters = [],
    array $options = [],
    int $status = 302,
    int $max_age = 86400,
  ): TrustedRedirectResponse {
    $options += ['absolute' => TRUE];
    $url = Url::fromRoute($route_name, $route_parameters, $options)
      ->toString(TRUE)
      ->getGeneratedUrl();
    // Since this is always an error route, we can tell everyone to cache it.
    $response = new TrustedRedirectResponse($url, $status,
      ['Cache-Control' => ["public", "max-age=$max_age"]],
    );
    $response->getCacheableMetadata()->setCacheMaxAge($max_age);

    // Return the response.
    return $response;
  }

}

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

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