From ce189a3f752e15bdeb92f620cff7a1fc72b8de41 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Wed, 31 Jul 2019 12:34:20 +1000
Subject: [PATCH] Issue #3067943 by andypost, jhodgdon, Amber Himes Matz,
 pwolanin: Add capability for search blocks on non-default search

---
 .../PageCacheTagsIntegrationTest.php          |  2 -
 .../search/config/schema/search.schema.yml    |  8 ++
 core/modules/search/search.post_update.php    | 24 +++++
 .../search/src/Form/SearchBlockForm.php       | 19 ++--
 .../search/src/Plugin/Block/SearchBlock.php   | 98 ++++++++++++++++++-
 .../tests/src/Functional/SearchBlockTest.php  | 31 +++++-
 .../Update/BlockPageSettingTest.php           | 39 ++++++++
 .../block.block.secondtestfor2354889.yml      |  1 +
 .../install/block.block.umami_search.yml      |  1 +
 .../install/block.block.bartik_search.yml     |  1 +
 10 files changed, 207 insertions(+), 17 deletions(-)
 create mode 100644 core/modules/search/search.post_update.php
 create mode 100644 core/modules/search/tests/src/Functional/Update/BlockPageSettingTest.php

diff --git a/core/modules/page_cache/tests/src/Functional/PageCacheTagsIntegrationTest.php b/core/modules/page_cache/tests/src/Functional/PageCacheTagsIntegrationTest.php
index 40cefba95287..dd41bc25daaf 100644
--- a/core/modules/page_cache/tests/src/Functional/PageCacheTagsIntegrationTest.php
+++ b/core/modules/page_cache/tests/src/Functional/PageCacheTagsIntegrationTest.php
@@ -111,7 +111,6 @@ public function testPageCacheTags() {
       'user:' . $author_1->id(),
       'config:filter.format.basic_html',
       'config:color.theme.bartik',
-      'config:search.settings',
       'config:system.menu.account',
       'config:system.menu.tools',
       'config:system.menu.footer',
@@ -152,7 +151,6 @@ public function testPageCacheTags() {
       'user:' . $author_2->id(),
       'config:color.theme.bartik',
       'config:filter.format.full_html',
-      'config:search.settings',
       'config:system.menu.account',
       'config:system.menu.tools',
       'config:system.menu.footer',
diff --git a/core/modules/search/config/schema/search.schema.yml b/core/modules/search/config/schema/search.schema.yml
index 2ed4c09ba9a8..64d75b8db9a9 100644
--- a/core/modules/search/config/schema/search.schema.yml
+++ b/core/modules/search/config/schema/search.schema.yml
@@ -88,3 +88,11 @@ search.page.*:
       label: 'Plugin'
     configuration:
       type: search.plugin.[%parent.plugin]
+
+block.settings.search_form_block:
+  type: block_settings
+  label: 'Search block'
+  mapping:
+    page_id:
+      type: string
+      label: 'Search page'
diff --git a/core/modules/search/search.post_update.php b/core/modules/search/search.post_update.php
new file mode 100644
index 000000000000..a6b1fd968b87
--- /dev/null
+++ b/core/modules/search/search.post_update.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Post update functions for Search module.
+ */
+
+use Drupal\block\BlockInterface;
+use Drupal\Core\Config\Entity\ConfigEntityUpdater;
+
+/**
+ * Configures default search page for instantiated blocks.
+ */
+function search_post_update_block_page(&$sandbox = NULL) {
+  if (!\Drupal::moduleHandler()->moduleExists('block')) {
+    // Early exit when block module disabled.
+    return;
+  }
+  \Drupal::classResolver(ConfigEntityUpdater::class)
+    ->update($sandbox, 'block', function (BlockInterface $block) {
+      // Save search block to set default search page from plugin.
+      return $block->getPluginId() === 'search_form_block';
+    });
+}
diff --git a/core/modules/search/src/Form/SearchBlockForm.php b/core/modules/search/src/Form/SearchBlockForm.php
index 0a373663bda8..4edcd73a1049 100644
--- a/core/modules/search/src/Form/SearchBlockForm.php
+++ b/core/modules/search/src/Form/SearchBlockForm.php
@@ -75,16 +75,17 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_id = NULL) {
     // Set up the form to submit using GET to the correct search page.
-    $entity_id = $this->searchPageRepository->getDefaultSearchPage();
-
-    // SearchPageRepository::getDefaultSearchPage() depends on search.settings.
-    // The dependency needs to be added before the conditional return, otherwise
-    // the block would get cached without the necessary cacheablity metadata in
-    // case there is no default search page and would not be invalidated if that
-    // changes.
-    $this->renderer->addCacheableDependency($form, $this->configFactory->get('search.settings'));
+    if (!$entity_id) {
+      $entity_id = $this->searchPageRepository->getDefaultSearchPage();
+      // SearchPageRepository::getDefaultSearchPage() depends on
+      // search.settings.  The dependency needs to be added before the
+      // conditional return, otherwise the block would get cached without the
+      // necessary cacheability metadata in case there is no default search page
+      // and would not be invalidated if that changes.
+      $this->renderer->addCacheableDependency($form, $this->configFactory->get('search.settings'));
+    }
 
     if (!$entity_id) {
       $form['message'] = [
diff --git a/core/modules/search/src/Plugin/Block/SearchBlock.php b/core/modules/search/src/Plugin/Block/SearchBlock.php
index d956d7ae3d69..d1a1f249fd22 100644
--- a/core/modules/search/src/Plugin/Block/SearchBlock.php
+++ b/core/modules/search/src/Plugin/Block/SearchBlock.php
@@ -3,8 +3,14 @@
 namespace Drupal\search\Plugin\Block;
 
 use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\search\Form\SearchBlockForm;
+use Drupal\search\SearchPageRepositoryInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a 'Search form' block.
@@ -15,7 +21,51 @@
  *   category = @Translation("Forms")
  * )
  */
-class SearchBlock extends BlockBase {
+class SearchBlock extends BlockBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface
+   */
+  protected $formBuilder;
+
+  /**
+   * The search page repository.
+   *
+   * @var \Drupal\search\SearchPageRepositoryInterface
+   */
+  protected $searchPageRepository;
+
+  /**
+   * Constructs a new SearchLocalTask.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
+   *   The form builder.
+   * @param \Drupal\search\SearchPageRepositoryInterface $search_page_repository
+   *   The search page repository.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, FormBuilderInterface $form_builder, SearchPageRepositoryInterface $search_page_repository) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->formBuilder = $form_builder;
+    $this->searchPageRepository = $search_page_repository;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition,
+      $container->get('form_builder'),
+      $container->get('search.search_page_repository')
+    );
+  }
 
   /**
    * {@inheritdoc}
@@ -28,7 +78,49 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function build() {
-    return \Drupal::formBuilder()->getForm('Drupal\search\Form\SearchBlockForm');
+    $page = $this->configuration['page_id'] ?? NULL;
+    return $this->formBuilder->getForm(SearchBlockForm::class, $page);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'page_id' => '',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, FormStateInterface $form_state) {
+    // The configuration for this block is which search page to connect the
+    // form to. Options are all configured/active search pages.
+    $options = [];
+    $active_search_pages = $this->searchPageRepository->getActiveSearchPages();
+    foreach ($this->searchPageRepository->sortSearchPages($active_search_pages) as $entity_id => $entity) {
+      $options[$entity_id] = $entity->label();
+    }
+
+    $form['page_id'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Search page'),
+      '#description' => $this->t('The search page that the form submits to, or Default for the default search page.'),
+      '#default_value' => $this->configuration['page_id'],
+      '#options' => $options,
+      '#empty_option' => $this->t('Default'),
+      '#empty_value' => '',
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, FormStateInterface $form_state) {
+    $this->configuration['page_id'] = $form_state->getValue('page_id');
   }
 
 }
diff --git a/core/modules/search/tests/src/Functional/SearchBlockTest.php b/core/modules/search/tests/src/Functional/SearchBlockTest.php
index eedb1a624386..31e16b13b993 100644
--- a/core/modules/search/tests/src/Functional/SearchBlockTest.php
+++ b/core/modules/search/tests/src/Functional/SearchBlockTest.php
@@ -15,14 +15,29 @@ class SearchBlockTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['block', 'node', 'search', 'dblog'];
+  protected static $modules = ['block', 'node', 'search', 'dblog', 'user'];
 
+  /**
+   * The administrative user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $adminUser;
+
+  /**
+   * {@inheritdoc}
+   */
   protected function setUp() {
     parent::setUp();
 
     // Create and log in user.
-    $admin_user = $this->drupalCreateUser(['administer blocks', 'search content']);
-    $this->drupalLogin($admin_user);
+    $this->adminUser = $this->drupalCreateUser([
+      'administer blocks',
+      'search content',
+      'access user profiles',
+      'access content',
+    ]);
+    $this->drupalLogin($this->adminUser);
   }
 
   /**
@@ -105,6 +120,16 @@ public function testSearchFormBlock() {
     $this->drupalPostForm(NULL, ['keys' => $this->randomMachineName()], t('Search'), [], 'search-form');
     $this->assertNoText('You must include at least one keyword to match in the content', 'Keyword message is not displayed when searching for long word after short word search');
 
+    // Edit the block configuration so that it searches users instead of nodes,
+    // and test.
+    $this->drupalPostForm('admin/structure/block/manage/' . $block->id(),
+      [
+        'settings[page_id]' => 'user_search',
+      ], 'Save block');
+    $name = $this->adminUser->getAccountName();
+    $email = $this->adminUser->getEmail();
+    $this->drupalPostForm('node', ['keys' => $name], t('Search'));
+    $this->assertLink($name);
   }
 
 }
diff --git a/core/modules/search/tests/src/Functional/Update/BlockPageSettingTest.php b/core/modules/search/tests/src/Functional/Update/BlockPageSettingTest.php
new file mode 100644
index 000000000000..d11ef0bdefdc
--- /dev/null
+++ b/core/modules/search/tests/src/Functional/Update/BlockPageSettingTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\Tests\search\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+
+/**
+ * Tests search blocks upgrade to default page setting.
+ *
+ * @group Update
+ * @group legacy
+ */
+class BlockPageSettingTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests existing search block settings upgrade.
+   *
+   * @see search_post_update_block_page()
+   */
+  public function testUpdateActionPlugins() {
+    $config = \Drupal::configFactory()->get('block.block.bartik_search');
+    $this->assertArrayNotHasKey('page_id', $config->get('settings'));
+
+    $this->runUpdates();
+
+    $config = \Drupal::configFactory()->get('block.block.bartik_search');
+    $this->assertSame('', $config->get('settings')['page_id']);
+  }
+
+}
diff --git a/core/modules/system/tests/fixtures/update/block.block.secondtestfor2354889.yml b/core/modules/system/tests/fixtures/update/block.block.secondtestfor2354889.yml
index 1a8a9046ffb0..e7ee5eda13f1 100644
--- a/core/modules/system/tests/fixtures/update/block.block.secondtestfor2354889.yml
+++ b/core/modules/system/tests/fixtures/update/block.block.secondtestfor2354889.yml
@@ -17,6 +17,7 @@ settings:
   label: Search
   provider: search
   label_display: visible
+  page_id: node_search
   cache:
     max_age: -1
   status: true
diff --git a/core/profiles/demo_umami/config/install/block.block.umami_search.yml b/core/profiles/demo_umami/config/install/block.block.umami_search.yml
index 047f516255a1..4acc93c78e1a 100644
--- a/core/profiles/demo_umami/config/install/block.block.umami_search.yml
+++ b/core/profiles/demo_umami/config/install/block.block.umami_search.yml
@@ -16,4 +16,5 @@ settings:
   label: Search
   provider: search
   label_display: visible
+  page_id: node_search
 visibility: {  }
diff --git a/core/profiles/standard/config/install/block.block.bartik_search.yml b/core/profiles/standard/config/install/block.block.bartik_search.yml
index 90b81cbfeef3..8a21f816dc6b 100644
--- a/core/profiles/standard/config/install/block.block.bartik_search.yml
+++ b/core/profiles/standard/config/install/block.block.bartik_search.yml
@@ -16,4 +16,5 @@ settings:
   label: Search
   provider: search
   label_display: visible
+  page_id: node_search
 visibility: {  }
-- 
GitLab