You are here

class SearchApiPageController in Search API Pages 8

Defines a controller to serve search pages.

Hierarchy

Expanded class hierarchy of SearchApiPageController

1 file declares its use of SearchApiPageController
SearchApiPageRoutes.php in src/Routing/SearchApiPageRoutes.php

File

src/Controller/SearchApiPageController.php, line 21

Namespace

Drupal\search_api_page\Controller
View source
class SearchApiPageController extends ControllerBase {

  /**
   * The parse mode plugin manager.
   *
   * @var \Drupal\search_api\ParseMode\ParseModePluginManager
   */
  protected $parseModePluginManager;

  /**
   * The parse mode pager manager.
   *
   * @var Drupal\Core\Pager\PagerManagerInterface
   */
  protected $pagerManager;

  /**
   * SearchApiPageController constructor.
   *
   * @param \Drupal\search_api\ParseMode\ParseModePluginManager $parseModePluginManager
   *   The parse mode plugin manager.
   * @param Drupal\Core\Pager\PagerManagerInterface $pagerManager
   *   The parse mode pager manager.
   */
  public function __construct(ParseModePluginManager $parseModePluginManager, PagerManagerInterface $pagerManager) {
    $this->parseModePluginManager = $parseModePluginManager;
    $this->pagerManager = $pagerManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('plugin.manager.search_api.parse_mode'), $container
      ->get('pager.manager'));
  }

  /**
   * Page callback.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   * @param string $search_api_page_name
   *   The search api page name.
   * @param string $keys
   *   The search word.
   *
   * @return array
   *   The page render array.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\search_api\SearchApiException
   */
  public function page(Request $request, $search_api_page_name, $keys = '') {

    /* @var $search_api_page \Drupal\search_api_page\SearchApiPageInterface */
    $search_api_page = $this
      ->entityTypeManager()
      ->getStorage('search_api_page')
      ->load($search_api_page_name);

    // Keys can be in the query.
    if (!$search_api_page
      ->getCleanUrl()) {
      $keys = $request
        ->get('keys');
    }
    $build['#theme'] = 'search_api_page';
    if ($search_api_page
      ->showSearchForm()) {
      $build = $this
        ->addSearchForm($build, $search_api_page, $keys);
    }
    if (empty($keys) && !$search_api_page
      ->showAllResultsWhenNoSearchIsPerformed()) {
      return $this
        ->finishBuild($build, $search_api_page);
    }
    $query = $this
      ->prepareQuery($request, $search_api_page);
    if (!empty($keys)) {
      $query
        ->keys($keys);
    }
    $result = $query
      ->execute();

    /* @var $items \Drupal\search_api\Item\ItemInterface[] */
    $items = $result
      ->getResultItems();
    $results = [];
    foreach ($items as $item) {
      $rendered = $this
        ->createItemRenderArray($item, $search_api_page);
      if ($rendered === []) {
        continue;
      }
      $results[] = $rendered;
    }
    if (empty($results)) {
      return $this
        ->finishBuildWithoutResults($build, $search_api_page);
    }
    return $this
      ->finishBuildWithResults($build, $result, $results, $search_api_page);
  }

  /**
   * Adds the search form to the build.
   *
   * @param array $build
   *   The build to add the form to.
   * @param \Drupal\search_api_page\SearchApiPageInterface $search_api_page
   *   The search api page.
   * @param mixed $keys
   *   The search word.
   *
   * @return array
   *   The build with the search form added to it.
   */
  protected function addSearchForm(array $build, SearchApiPageInterface $search_api_page, $keys) {
    $block_form = \Drupal::getContainer()
      ->get('block_form.search_api_page');
    $block_form
      ->setPageId($search_api_page
      ->id());
    $args = [
      'keys' => $keys,
    ];
    $build['#form'] = $this
      ->formBuilder()
      ->getForm($block_form, $args);
    return $build;
  }

  /**
   * Creates a render array for the given result item.
   *
   * @param \Drupal\search_api\Item\ItemInterface $item
   *   The item to render.
   * @param \Drupal\search_api_page\SearchApiPageInterface $search_api_page
   *   The search api page.
   *
   * @return array
   *   A render array for the given result item.
   */
  protected function createItemRenderArray(ItemInterface $item, SearchApiPageInterface $search_api_page) {
    try {
      $originalObject = $item
        ->getOriginalObject();
      if ($originalObject === NULL) {
        return [];
      }

      /** @var \Drupal\Core\Entity\EntityInterface $entity */
      $entity = $originalObject
        ->getValue();
    } catch (SearchApiException $e) {
      return [];
    }
    if (!$entity) {
      return [];
    }
    $viewedResult = [];
    if ($search_api_page
      ->renderAsViewModes()) {
      $datasource_id = 'entity:' . $entity
        ->getEntityTypeId();
      $bundle = $entity
        ->bundle();
      $viewMode = $search_api_page
        ->getViewModeConfig()
        ->getViewMode($datasource_id, $bundle);
      $viewedResult = $this
        ->entityTypeManager()
        ->getViewBuilder($entity
        ->getEntityTypeId())
        ->view($entity, $viewMode);
      $viewedResult['#search_api_excerpt'] = $item
        ->getExcerpt();
    }
    if ($search_api_page
      ->renderAsSnippets()) {
      $viewedResult = [
        '#theme' => 'search_api_page_result',
        '#item' => $item,
        '#entity' => $entity,
      ];
    }
    $metadata = CacheableMetadata::createFromRenderArray($viewedResult);
    $metadata
      ->addCacheContexts([
      'url.path',
    ]);
    $metadata
      ->addCacheTags([
      'search_api_page.style',
    ]);
    $metadata
      ->applyTo($viewedResult);
    return $viewedResult;
  }

  /**
   * Finishes the build.
   *
   * @param array $build
   *   An array containing all page elements.
   * @param \Drupal\search_api_page\SearchApiPageInterface $searchApiPage
   *   The Search API page entity.
   * @param \Drupal\search_api\Query\ResultSetInterface $result
   *   Search API result.
   *
   * @return array
   *   An array containing all page elements.
   */
  protected function finishBuild(array $build, SearchApiPageInterface $searchApiPage, ResultSetInterface $result = NULL) {
    $this
      ->moduleHandler()
      ->alter('search_api_page', $build, $result, $searchApiPage);

    // TODO caching dependencies.
    // @see https://www.drupal.org/project/search_api_page/issues/2754411.
    return $build;
  }

  /**
   * Prepares the search query.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   * @param \Drupal\search_api_page\SearchApiPageInterface $search_api_page
   *   The search api page.
   *
   * @return \Drupal\search_api\Query\QueryInterface
   *   The prepared query.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\search_api\SearchApiException
   */
  protected function prepareQuery(Request $request, SearchApiPageInterface $search_api_page) {

    /* @var $search_api_index \Drupal\search_api\IndexInterface */
    $search_api_index = $this
      ->entityTypeManager()
      ->getStorage('search_api_index')
      ->load($search_api_page
      ->getIndex());
    $query = $search_api_index
      ->query([
      'limit' => $search_api_page
        ->getLimit(),
      'offset' => $request
        ->get('page') !== NULL ? $request
        ->get('page') * $search_api_page
        ->getLimit() : 0,
    ]);
    $query
      ->setSearchID('search_api_page:' . $search_api_page
      ->id());

    /** @var \Drupal\search_api\ParseMode\ParseModeInterface $parse_mode */
    $parse_mode = $this->parseModePluginManager
      ->createInstance($search_api_page
      ->getParseMode());
    $query
      ->setParseMode($parse_mode);

    // Add filter for current language.
    $langcode = $this
      ->languageManager()
      ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
      ->getId();
    $query
      ->setLanguages([
      $langcode,
      LanguageInterface::LANGCODE_NOT_SPECIFIED,
    ]);
    $query
      ->setFulltextFields($search_api_page
      ->getSearchedFields());
    return $query;
  }

  /**
   * Adds the no results text and then finishes the build.
   *
   * @param array $build
   *   The build to finish.
   * @param \Drupal\search_api_page\SearchApiPageInterface $searchApiPage
   *   The Search API page entity.
   *
   * @return array
   *   The finished build render array.
   */
  protected function finishBuildWithoutResults(array $build, SearchApiPageInterface $searchApiPage) {
    $build['#no_results_found'] = [
      '#markup' => $this
        ->t('Your search yielded no results.'),
    ];
    $build['#search_help'] = [
      '#markup' => $this
        ->t('<ul>
<li>Check if your spelling is correct.</li>
<li>Remove quotes around phrases to search for each word individually. <em>bike shed</em> will often show more results than <em>&quot;bike shed&quot;</em>.</li>
<li>Consider loosening your query with <em>OR</em>. <em>bike OR shed</em> will often show more results than <em>bike shed</em>.</li>
</ul>'),
    ];
    return $this
      ->finishBuild($build, $searchApiPage);
  }

  /**
   * Adds the results to the given build and then finishes it.
   *
   * @param array $build
   *   The build.
   * @param \Drupal\search_api\Query\ResultSetInterface $result
   *   Search API result.
   * @param array $results
   *   The result item render arrays.
   * @param \Drupal\search_api_page\SearchApiPageInterface $search_api_page
   *   The search api page.
   *
   * @return array
   *   The finished build.
   */
  protected function finishBuildWithResults(array $build, ResultSetInterface $result, array $results, SearchApiPageInterface $search_api_page) {
    $build['#search_title'] = [
      '#markup' => $this
        ->t('Search results'),
    ];
    $build['#no_of_results'] = [
      '#markup' => $this
        ->formatPlural($result
        ->getResultCount(), '1 result found', '@count results found'),
    ];
    $build['#results'] = $results;
    $this->pagerManager
      ->createPager($result
      ->getResultCount(), $search_api_page
      ->getLimit());
    $build['#pager'] = [
      '#type' => 'pager',
    ];
    return $this
      ->finishBuild($build, $search_api_page, $result);
  }

  /**
   * Title callback.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   * @param string $search_api_page_name
   *   The search api page name.
   * @param string $keys
   *   The search word.
   *
   * @return string
   *   The page title.
   */
  public function title(Request $request, $search_api_page_name = NULL, $keys = '') {

    // Provide a default title if no search API page name is provided.
    if ($search_api_page_name === NULL) {
      return $this
        ->t('Search');
    }

    /* @var $search_api_page \Drupal\search_api_page\SearchApiPageInterface */
    $search_api_page = SearchApiPage::load($search_api_page_name);
    return $search_api_page
      ->label();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ControllerBase::$configFactory protected property The configuration factory.
ControllerBase::$currentUser protected property The current user service. 1
ControllerBase::$entityFormBuilder protected property The entity form builder.
ControllerBase::$entityManager protected property The entity manager.
ControllerBase::$entityTypeManager protected property The entity type manager.
ControllerBase::$formBuilder protected property The form builder. 2
ControllerBase::$keyValue protected property The key-value storage. 1
ControllerBase::$languageManager protected property The language manager. 1
ControllerBase::$moduleHandler protected property The module handler. 2
ControllerBase::$stateService protected property The state service.
ControllerBase::cache protected function Returns the requested cache bin.
ControllerBase::config protected function Retrieves a configuration object.
ControllerBase::container private function Returns the service container.
ControllerBase::currentUser protected function Returns the current user. 1
ControllerBase::entityFormBuilder protected function Retrieves the entity form builder.
ControllerBase::entityManager Deprecated protected function Retrieves the entity manager service.
ControllerBase::entityTypeManager protected function Retrieves the entity type manager.
ControllerBase::formBuilder protected function Returns the form builder service. 2
ControllerBase::keyValue protected function Returns a key/value storage collection. 1
ControllerBase::languageManager protected function Returns the language manager service. 1
ControllerBase::moduleHandler protected function Returns the module handler. 2
ControllerBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
ControllerBase::state protected function Returns the state storage service.
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
SearchApiPageController::$pagerManager protected property The parse mode pager manager.
SearchApiPageController::$parseModePluginManager protected property The parse mode plugin manager.
SearchApiPageController::addSearchForm protected function Adds the search form to the build.
SearchApiPageController::create public static function Instantiates a new instance of this class. Overrides ControllerBase::create
SearchApiPageController::createItemRenderArray protected function Creates a render array for the given result item.
SearchApiPageController::finishBuild protected function Finishes the build.
SearchApiPageController::finishBuildWithoutResults protected function Adds the no results text and then finishes the build.
SearchApiPageController::finishBuildWithResults protected function Adds the results to the given build and then finishes it.
SearchApiPageController::page public function Page callback.
SearchApiPageController::prepareQuery protected function Prepares the search query.
SearchApiPageController::title public function Title callback.
SearchApiPageController::__construct public function SearchApiPageController constructor.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.