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

src/Controller/Homonyms.php
<?php

declare(strict_types=1);

namespace Drupal\g2\Controller;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\g2\G2;
use Drupal\node\NodeInterface;
use Drupal\views\ViewEntityInterface;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Class Homonyms contains the controller for the entry list pages.
 *
 * Pages are:
 * - Entries by full name.
 * - Entries by initial.
 *
 * @phpstan-consistent-constructor
 */
class Homonyms implements ContainerInjectionInterface {

  use StringTranslationTrait;

  /**
   * Title of the G2 by-initial pages.
   */
  const ENTRIES_BY_INITIAL = 'G2 entries starting with initial %initial';

  /**
   * The config.factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

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

  /**
   * Homonyms constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
   *   The entity_type.manager service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The g2.settings/controller.homonyms configuration.
   */
  public function __construct(EntityTypeManagerInterface $entity_manager, ConfigFactoryInterface $configFactory) {
    $this->etm = $entity_manager;
    $this->configFactory = $configFactory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    /** @var \Drupal\Core\Config\ConfigFactoryInterface $configFactory */
    $configFactory = $container->get(G2::SVC_CONF);

    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
    $etm = $container->get(G2::SVC_ETM);
    return new static($etm, $configFactory);
  }

  /**
   * Build a "no match" themed response.
   *
   * @param string $raw_match
   *   The raw, unsafe string requested.
   *
   * @return array<string,mixed>
   *   A render array.
   *
   * @FIXME passing "+" (unquoted) causes notice in getAliasByPath().
   */
  protected function indexNoMatch($raw_match): array {
    $message = $this->t('There are currently no entries for %entry.', ['%entry' => $raw_match]);

    $may_create = $this->etm
      ->getAccessControlHandler(G2::TYPE)
      ->createAccess(G2::BUNDLE);
    if ($may_create) {
      $arguments = [
        'node_type' => G2::BUNDLE,
      ];
      $options = [
        'query' => ['title' => urlencode($raw_match)],
      ];
      $offer = $this->t('Would you like to <a href=":url" title="Create new entry for @entry">create one</a> ?', [
        ':url' => Url::fromRoute('node.add', $arguments, $options)->toString(),
        '@entry' => $raw_match,
      ]);
    }
    else {
      $offer = NULL;
    }

    $result = [
      '#theme' => 'g2_entries',
      '#offer' => $offer,
      '#message' => $message,
    ];

    return $result;
  }

  /**
   * Build a redirect response to the matching G2 entry canonical URL.
   *
   * @param \Drupal\node\NodeInterface[] $g2_match
   *   The match array, containing a single node entity.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   The redirect response.
   */
  protected function indexRedirectSingleMatch(array $g2_match) {
    $status = $this->configFactory
      ->get(G2::CONFIG_NAME)
      ->get(G2::VARHOMONYMSREDIRECTSTATUS);
    assert(is_int($status) && ($status === 201 || ($status >= 300 && $status <= 399)),
      'redirect is a redirect');
    assert(count($g2_match) !== 0);
    /** @var \Drupal\Core\Entity\EntityInterface $node */
    $node = reset($g2_match);
    $redirect = $node->toUrl()->toString();
    $response = new RedirectResponse($redirect, $status);
    return $response;
  }

  /**
   * Build the generic multi-match themed response.
   *
   * @param string $raw_match
   *   The raw, unsafe string requested.
   * @param \Drupal\node\NodeInterface[] $g2_match
   *   The match array, containing node entities indexed by nid.
   *
   * @return array<string,mixed>
   *   A render array.
   */
  protected function indexMatches($raw_match, array $g2_match): array {
    $entries = $this->etm
      ->getViewBuilder(G2::TYPE)
      ->viewMultiple($g2_match, G2::VM_ENTRY_LIST);
    $result = [
      '#theme' => 'g2_entries',
      '#raw_entry' => $raw_match,
      '#entries' => $entries,
    ];
    return $result;
  }

  /**
   * Build a homonyms page using a node instead of the match information.
   *
   * This is an old feature, included for compatibility with antique versions,
   * but it is better to avoid it and use a custom route instead, which will be
   * able to take advantage of the converted parameters and have versions code.
   *
   * @param int $nid
   *   The node to use to build the page.
   *
   * @return array<string,mixed>
   *   A render array.
   *
   * @deprecated in g2:8.x-1.0 and is removed from g2:8.x-2.0. Use a view.
   * @see https://www.drupal.org/project/g2/issues/3369887
   */
  protected function indexUsingNode($nid): array {
    /** @var \Drupal\node\NodeInterface $node */
    $node = $this->etm
      ->getStorage(G2::TYPE)
      ->load($nid);
    $builder = $this->etm
      ->getViewBuilder(G2::TYPE);
    $result = $builder->view($node, G2::VM_HOMONYMS_PAGE);
    return $result;
  }

  /**
   * Build a homonyms page using a view instead of the match information.
   *
   * View is invoked using the unsafe raw_match.
   *
   * @param string $raw_match
   *   The raw, unsafe string requested.
   * @param string $view_id
   *   The id of the view to use.
   *
   * @return array<string,mixed>
   *   A render array.
   */
  protected function indexUsingView(string $raw_match, string $view_id): array {
    /** @var \Drupal\views\ViewEntityInterface $view */
    $view = $this->etm->getStorage('view')->load($view_id);
    assert($view instanceof ViewEntityInterface);

    $executable = $view->getExecutable();
    assert($executable instanceof ViewExecutable);

    $result = $executable->access('default')
      ? $executable->preview('default', [$raw_match]) ?: []
      : [];

    return $result;
  }

  /**
   * Controller for g2.homonyms.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route
   *   The current route.
   * @param \Drupal\node\NodeInterface[] $g2_match
   *   Unsafe. The entry for which to find matching G2 entries.
   *
   * @return array<string,mixed>|\Symfony\Component\HttpFoundation\RedirectResponse
   *   Render array or redirect response.
   */
  public function indexAction(RouteMatchInterface $route, array $g2_match): array|RedirectResponse {
    $raw_match = $route->getRawParameter('g2_match') ?: '';

    if (empty($g2_match)) {
      return $this->indexNoMatch($raw_match);
    }

    $settings = $this->configFactory->get(G2::CONFIG_NAME);

    $matches = array_filter($g2_match, fn(NodeInterface $node) => $node->label() === $raw_match);
    switch (count($matches)) {
      /* @noinspection PhpMissingBreakStatementInspection */
      case 1:
        $redirect = $settings->get(G2::VARHOMONYMSREDIRECTSINGLE);
        if ($redirect) {
          $result = $this->indexRedirectSingleMatch($matches);
          break;
        }
        /* Single match handled as any other non-0 number, so fall through. */

      default:
        $nid = $settings->get(G2::VARHOMONYMSNID);
        assert(is_scalar($nid));
        $nid = (int) $nid;
        $vid = $settings->get(G2::VARHOMONYMSVID);
        assert(is_scalar($vid));
        $vid = (string) $vid;
        if (!empty($nid)) {
          $result = $this->indexUsingNode($nid);
        }
        elseif (!empty($vid)) {
          $result = $this->indexUsingView($raw_match, $vid);
        }
        else {
          $result = $this->indexMatches($raw_match, $matches);
        }
        break;
    }
    if (empty($result)) {
      $result = ['#plain_text' => $this->t('No matching entry found.')];
    }
    return $result;
  }

  /**
   * Title callback for g2.homonyms.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route
   *   The current route match.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The page title.
   */
  public function indexTitle(RouteMatchInterface $route) {
    $raw_match = $route->getRawParameter('g2_match');
    return $this->t('%entry may refer to:', ['%entry' => $raw_match]);
  }

}

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

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