diff --git a/.envrc.dist b/.envrc.dist
index b18f4442..a0031c90 100644
--- a/.envrc.dist
+++ b/.envrc.dist
@@ -9,3 +9,4 @@ export PANTHEON_INDEX_PORT=8983
export PANTHEON_INDEX_PATH=/solr
export PANTHEON_INDEX_CORE=${SOLR_CORE}
export PANTHEON_INDEX_SCHEME=http
+export PANTHEON_INDEX_RELOAD_PATH=${SOLR_RELOAD_PATH}
diff --git a/.gitignore b/.gitignore
index 5b0d6ba4..6baa65bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@
.idea
.DS_Store
docs/Badge.confluence
+
+.envrc
diff --git a/README.md b/README.md
index 2bed0a9f..b69fdde9 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,41 @@
-# Search API Pantheon version 8.0 (for solr 8 & Drupal 9/10)
+# Search API Pantheon: Solr 8 & Drupal 9/10 Integration
[![Search API Pantheon](https://github.com/pantheon-systems/search_api_pantheon/actions/workflows/ci.yml/badge.svg?branch=8.x)](https://github.com/pantheon-systems/search_api_pantheon/actions/workflows/ci.yml)
[![Limited Availability](https://img.shields.io/badge/Pantheon-Limited_Availability-yellow?logo=pantheon&color=FFDC28)](https://pantheon.io/docs/oss-support-levels#limited-availability)
+## Important Notice - Schema Reversion Prevention
-![Solr at pantheon diagram](docs/diagram.svg "Solr at pantheon")
+Starting with version 8.2, this module includes critical fixes to prevent Solr schema reversions that could cause:
-## Requirements
-
-This module is for you if you meet the following requirements:
+- Search functionality outages
+- Loss of indexed content
+- Unexpected schema reversions
+- Site downtime
-* Using Drupal 9.4/10
+Users experiencing these issues should upgrade immediately to version 8.1.x-dev.
-* Hosting the Drupal site on Pantheon's platform
+## Requirements
-* Your site uses `composer` to install modules and upgrade Drupal core using one of the following integrations:
+This module is for you if you meet the following requirements:
- * Pantheon's integrated composer (`build step: true` in your pantheon.yml)
+- Using Drupal 9.4/10
+- Hosting the Drupal site on Pantheon's platform
+- Your site uses `composer` to install modules and upgrade Drupal core using one of the following integrations:
- * A Continuous Integration service like Circle CI or Travis
+ - Pantheon's integrated composer (`build step: true` in your pantheon.yml)
+ - A Continuous Integration service like Circle CI or Travis
-* Have Dashboard access to the platform (necessary to deploy code changes)
+- Have Dashboard access to the platform (necessary to deploy code changes)
## Intent
-This module is meant to simplify the usage of [Search API](https://www.drupal.org/project/search_api)
-and [Search API Solr](https://www.drupal.org/project/search_api_solr) on [Pantheon](https://pantheon.io)'s Platform.
+This module is meant to simplify the usage of [Search API](https://www.drupal.org/project/search_api) and [Search API Solr](https://www.drupal.org/project/search_api_solr) on [Pantheon](https://pantheon.io)'s Platform.
-Search API Solr provides the ability to connect to any Solr server by providing numerous configuration options.
-This module automatically sets the Solr connection options by extending the plugin from Search API Solr.
-The module also changes its connection information based on different Pantheon environments and each
-Pantheon Environment has it's own [SOLR CORE](#). Doing so eliminates the need to do extra work setting up Solr servers for each environment.
+Search API Solr provides the ability to connect to any Solr server by providing numerous configuration options. This module automatically sets the Solr connection options by extending the plugin from Search API Solr. The module also changes its connection information based on different Pantheon environments and each Pantheon Environment has its own [SOLR CORE](#). Doing so eliminates the need to do extra work setting up Solr servers for each environment.
## What it provides
-This module provides [Drupal 9](https://drupal.org) integration with the [Apache Solr project](https://solr.apache.org/guide/8_8/).
-Pantheon's current version as of the update of this document is 8.8.1.
+This module provides [Drupal 9 and 10](https://drupal.org) integration with the [Apache Solr project](https://solr.apache.org/guide/8_8/). Pantheon's current version as of the update of this document is 8.11.4.
## Composer
@@ -44,43 +44,46 @@ Composer is the way you should be managing your drupal module requirements. This
## Dependencies (installed by Composer):
- [Solarium](http://www.solarium-project.org/). Solarium is a Solr client library for PHP and is not Drupal-specific. First, register Drupal.org as a provider of Composer packages. This command should be run locally from the root directory of your Drupal 8 git repository.
-
- [Search API](https://www.drupal.org/project/search_api). Search API is Drupal's module for indexing content entities.
-
- [Search API Solr](https://www.drupal.org/project/search_api_solr). Search API Solr makes search API work with Apache Solr. Composer will manage which version.
-
- [Guzzle](https://docs.guzzlephp.org/en/stable/). Guzzle version 6 is standard with Drupal Core `9.x | 10.x` (read 9.x OR 10.x).
## Install
-To require this module in your composer file:
+### Stable Release
+To install this module via composer, run the following command in your Drupal root:
+
+```bash
+composer require 'drupal/search_api_pantheon:^8.1'
```
-composer require pantheon-systems/search_api_pantheon ^8 --prefer-dist
-```
-Install the module and push an updated `composer.lock` file to your Pantheon environment.
+### Development Version
+
+Note that the above will install the latest stable release of this module. To install the latest development version, use:
+
+```bash
+composer require 'drupal/search_api_pantheon:8.1.x-dev@dev'
+```
## Setup
-### PLATFORM SUPPORT
+### Platform Support
See [Drupal.org for complete documentation on Search API](https://www.drupal.org/node/1250878).
To configure the connection with Pantheon, perform the following steps on your Dev environment (or a Multidev):
-* **Enable Solr on your Pantheon site**
-
- * Under "Settings" in your Pantheon site dashboard, enable Solr as an add on.
+#### Enable Solr on your Pantheon site
+ - Under "Settings" in your Pantheon site dashboard, enable Solr as an add on.
This feature is available for sandbox sites as well as paid plans at the
Professional level and above.
-* **Enable Solr 8 in your pantheon.yml file**
+#### Enable Solr 8 in your pantheon.yml file
- * Add the bolded portion to your `pantheon.yml` file (** SYNTAX NOT FINAL; Use pantheon internal YGG
- instructions until yml support is final and available in prod **):
+ - Add the bolded portion to your `pantheon.yml` file:
```yaml
- php_version: 7.4
+ php_version: 8.1
database:
version: 10.4
drush_version: 10
@@ -93,144 +96,158 @@ To configure the connection with Pantheon, perform the following steps on your D
and ensure the content is indexed after creation. Indices are specific to the Solr core
with/for which they were created. Indices cannot be exported or moved once created.
-### USAGE
+### Core Reloading
-* **Enable the modules**
+#### Automatic Core Reload
- * Go to `admin/modules` and enable "Search API Pantheon."
+Starting with version 8.1.x, Search API Pantheon automatically reloads the Solr core after schema updates to prevent schema reversions and maintain index integrity.
- * Doing so will also enable Search API and Search API Solr if they are not already enabled.
+#### Schema Updates
-* **OPTIONAL: Disable Drupal Core's search module**
+Schema updates can be performed through:
- * If you are using Search API, then you probably will not be using Drupal Core's Search module.
+- Admin UI: Navigate to `/admin/config/search/search-api/server/pantheon_solr8/pantheon-admin/schema`
+- Drush: Run `drush search-api-pantheon:postSchema`
- * Uninstall it to save some confusion in the further configuration steps: `admin/modules/uninstall`.
+#### Manual Core Reload
+
+If needed, manually reload the core using:
+
+```bash
+drush search-api-pantheon:reload
+```
-* **The module should install a SEARCH API server for you**
+### Usage
- * Navigate in the Drupal interface to `CONFIG` => `SEARCH & METADATA` => `SEARCH API`
+#### Enable the modules
- * Validate that the `PANTHEON SEARCH` server exists and is "enabled".
+ - Go to `admin/modules` and enable "Search API Pantheon."
+ - Doing so will also enable Search API and Search API Solr if they are not already enabled.
-* **Solr versions and schemas**
+#### OPTIONAL: Disable Drupal Core's search module
- * The version of Solr on Pantheon is Apache Solr 8.8. When you first create
+ - If you are using Search API, then you probably will not be using Drupal Core's Search module.
+ - Uninstall it to save some confusion in the further configuration steps: `admin/modules/uninstall`.
+
+#### The module should install a SEARCH API server for you
+
+ - Navigate in the Drupal interface to `CONFIG` => `SEARCH & METADATA` => `SEARCH API`
+ - Validate that the `PANTHEON SEARCH` server exists and is "enabled".
+
+#### Solr versions and schemas
+
+ - The version of Solr on Pantheon is Apache Solr 8.8. When you first create
your index or alter it significantly, you will need to update the SCHEMA
on the server. Do that either with a drush command or in the administration
for the Solr Server.
-
- * Navigate to `CONFIGURATION` => `SEARCH AND METADATA` => `SEARCH API`
+ - Navigate to `CONFIGURATION` => `SEARCH AND METADATA` => `SEARCH API`
=> `PANTHEON SEARCH` => `PANTHEON SEARCH ADMIN`
+ - Choose the button labeled "Post Solr Schema".
+ - The module will post a schema specific to your site.
- * Choose the button labeled "Post Solr Schema".
-
- * The module will post a schema specific to your site.
-
-* **Use the server with an index**
+#### Use the server with an index
The following steps are not Pantheon-specific. This module only alters the the configuration of Search API servers. To use a server, you next need to create an index.
- * Go to `admin/config/search/search-api/add-index`.
-
- * Name your index and choose a data source. If this is your
+ - Go to `admin/config/search/search-api/add-index`.
+ - Name your index and choose a data source. If this is your
first time using Search API, start by selecting "Content"
as a data source. That option will index the articles,
basic pages, and other node types you have configured.
-
- * Select "Pantheon" as the server.
-
- * Save the index.
-
- * For this index to be usable, you will also need to configure fields to be searched.
+ - Select "Pantheon" as the server.
+ - Save the index.
+ - For this index to be usable, you will also need to configure fields to be searched.
Select the "fields" tab and `CHOOSE FIELDS TO BE INCLUDED IN THE INDEX`. You may want
to index many fields. "Title" is a good field to start with.
-
- * After adding fields to the configuration, make sure the index is full by clicking
+ - After adding fields to the configuration, make sure the index is full by clicking
"Index now" or by running cron.
-* **Search the Index**
+#### Search the Index
- * Create a new view returning `INDEX PANTHEON SOLR8` of type 'ALL'. Don't worry right now how it's sorted, we're
+ - Create a new view returning `INDEX PANTHEON SOLR8` of type 'ALL'. Don't worry right now how it's sorted, we're
going to change that to 'relevance' once we have some data being returned during the search.
-
- * In the view, `CHOOSE FIELDS TO BE INCLUDED IN THE RESULTS` from the fields you added to your index
+ - In the view, `CHOOSE FIELDS TO BE INCLUDED IN THE RESULTS` from the fields you added to your index
when you created it. In addition to the fields you added to the index, choose 'relevance' to add
to the results.
-
- * Expose any keywords to the user to change and the view will put a KEYWORDS
-
- * Once your search is returning results, you can now sort by the "relevance" field and Solr will give the documents
+ - Expose any keywords to the user to change and the view will put a KEYWORDS
+ - Once your search is returning results, you can now sort by the "relevance" field and Solr will give the documents
a relevance rating. A higher rating means Solr thinks the item is "more relevant" to your search term.
-* **Export your changes**
+#### Export your changes
- * It is a best practice in Drupal 8 to export your changes to `yml` files.
- Using Terminus while in SFTP mode, you can run `terminus --env=dev drush "config-export -y"`
+ - It is a best practice in Drupal z to export your changes to `yml` files.
+ Using Terminus while in SFTP mode, you can run `terminus drush [PANTHEON_SITE].[PANTHEON_ENV] -- "config:export -y"`
to export the configuration changes you have made. Once committed, these changes
can be deployed out to Test and Live environments.
-* **OPTIONAL INSTALLS**
+#### Optional Installs
Any of the optional `search_api` modules should work without issue with Pantheon Solr, including but not limited to:
- * Search API Attachments
-
- * Search API Facets
+ - Search API Attachments
+ - Search API Facets
+ - Search API Autocomplete
+ - Search API Spellcheck
+ - Search API Ajax
- * Search API Autocomplete
-
- * Search API Spellcheck
-
- * Search API Ajax
-
-### Pantheon environments
+## Pantheon Environments
Each Pantheon environment (Dev, Test, Live, and Multidevs) has its own Solr server. Indexing and searching in one environment does not impact any other environment.
-### Feedback and collaboration
+## Solr Jargon
-Bug reports, feature requests, and feedback should be posted in [the drupal.org issue queue.](https://www.drupal.org/project/issues/search_api_pantheon?categories=All) For code changes, please submit pull requests against the [GitHub repository](https://github.com/pantheon-systems/search_api_pantheon) rather than posting patches to drupal.org.
+| Term | Definition |
+| ---------- | ---------------------------------------------------------------------------------- |
+| Commit | To make document changes permanent in the index. |
+| Core | An instance of the Solr server suitable for creating zero or more indices. |
+| Collection | Solr Cloud's version of a "CORE". Not currently used at Pantheon. |
+| Document | A group of fields and their values. The basic unit of data in a collection. |
+| Facet | The arrangement of search results into categories based on indexed terms. |
+| Field | The content to be indexed/searched along with metadata. |
+| Index | A group of metadata entries gathered by Solr into a searchable catalog. |
+| Schema | A series of plain text and XML files that describe the data Solr will be indexing. |
+## Troubleshooting
-# SOLR JARGON:
+### Schema Reversion Issues
-Much of the jargon used in the Solr paradigm is used elsewhere in both Drupal and other technologies. Please familiarize yourself
-with the concept usage in a Solr context:
+If you experience schema reversion issues:
-* **Commit** - To make document changes permanent in the index. In the case of added documents, they would be searchable after a commit.
+1. Verify you're using version 8.1.x-dev or later
+2. Check that core reloading is functioning after schema updates
+3. Monitor the Drupal logs for schema update messages
+4. Use `drush search-api-pantheon:diagnose` to verify configuration
-* **Core** - An instance of the Solr server suitable for creating zero or more indices. Solr core is a way to represent a Lucene index
- and a set of configurations that control the accessing and using of the index with Solr. It's the main object you will interact
- with when working with Solr. You will create it, configure it, index data in it and preform queries on it. A Solr core
- is a Lucene index but wrapped in Solr related configurations.
+### Common Issues
-* **Collection** - Solr Cloud's version of a "CORE". Not currently used at Pantheon.
+| Issue | Solution |
+| --------------------------- | --------------------------------------------- |
+| Schema reverts unexpectedly | Ensure core reload is happening after updates |
+| Search index corruption | Try reposting schema and reindexing content |
+| Core reload failures | Check Solr logs and connection status |
-* **Document** - A group of fields and their values. Documents are the basic unit of data in a collection.
- Documents are assigned to shards using standard hashing, or by specifically assigning a shard within
- the document ID. Documents are versioned after each write operation. Not to be confused with a PDF
- document which can be uploaded to Solr and searched via the SearchAPIAttachments module.
+### Diagnostic Commands
+
+- `drush search-api-pantheon:diagnose` (`sapd`) The DIAGNOSE command will check the various pieces of the Search API install
+ and throw errors on the pieces that are not working. This command will develop further as the module nears general availability.
-* **Facet** - The arrangement of search results into categories based on indexed terms.
+- `drush search-api-pantheon:select` (`saps`) This command will run the given query against Solr server. It's recommended to use
+ `?debug=true` in any Solr page (having the right permissions) to get a good query to pass to this command to debug results.
-* **Field** - The content to be indexed/searched along with metadata defining how the content should be processed by Solr.
+- `drush search-api-pantheon:force-cleanup` (`sapfc`) This command will delete all of the contents for the given
+ Solr server (no matter if hash or index_id have changed).
-* **Index** - A group of metadata entries gathered by Solr into a searchable catalog.
+- `drush search-api-pantheon:postSchema [solr-server] [path-to-schema]` (`sapps`) This command will upload schema files to the solr server. It can be used to reset a solr schema to the default Pantheon configuration, upgrade a schema, or to use a custom config set.
-* **Schema** - A series of plain text and XML files that describe the data Solr will be indexing. The schema tells the server
- about the data that Solr will be indexing and tells Solr how to return the results. Schema is generated automatically
- by Drupal and uploaded using the `PANTHEON_ADMIN` tab of this module.
+The current default schema on Pantheon when a new Solr container is provisioned is the 4.2.1 version of the solr8 jump-start config set provided by the Search API Solr module. To upgrade the default Pantheon solr 8 server to a version 4.3.0+ compatible config set, run the following command after you've upgraded the Search API Solr module to your desired version.
+`drush search-api-pantheon:postSchema pantheon_solr8 /code/web/modules/contrib/search_api_solr/jump-start/solr8/config-set/`
-# TROUBLESHOOTING
+Once you have enabled the Search API Pantheon module, when you reload the schema the Pantheon module will use the config-set for the version of the Search API Solr module installed in your codebase. See the [Search API Solr 4.3.0 release notes](https://www.drupal.org/project/search_api_solr/releases/4.3.0) for more information about upgrading to a 4.3.0+ compatible schema.
-* `drush search-api-pantheon:diagnose` (`sapd`) The DIAGNOSE command will check the various pieces of the Search API install
- and throw errors on the pieces that are not working. This command will develop further as the module nears general availability.
+- `drush search-api-pantheon:test-index-and-query` (`sap-tiq`) This command will connect to the solr8 server to index a single item and immediately query it.
-* `drush search-api-pantheon:select` (`saps`) This command will run the given query against Solr server. It's recommended to use
- `?debug=true` in any Solr page (having the right permissions) to get a good query to pass to this command to debug results.
+## Feedback and Collaboration
+Bug reports, feature requests, and feedback should be posted in [the drupal.org issue queue.](https://www.drupal.org/project/issues/search_api_pantheon?categories=All) For code changes, please submit pull requests against the [GitHub repository](https://github.com/pantheon-systems/search_api_pantheon).
-* `drush search-api-pantheon:force-cleanup` (`sapfc`) This command will delete all of the contents for the given
- Solr server (no matter if hash or index_id have changed).
diff --git a/RoboFile.php b/RoboFile.php
index bc25bcf2..1fc32bba 100644
--- a/RoboFile.php
+++ b/RoboFile.php
@@ -117,6 +117,10 @@ public function testFull(int $drupal_version = 9, string $site_name = NULL) {
// Test creating Solr index.
$this->testSolrIndexCreate($site_name, 'dev');
+ // Test running the reload
+ $this->testPantheonSolrReload($site_name, 'dev');
+ $this->testSolrReload($site_name, 'dev');
+
// Test select query.
$this->testSolrSelect($site_name, 'dev');
@@ -573,6 +577,7 @@ public function testModuleEnable(string $site_name, string $env = 'dev') {
'--yes',
'search_api_pantheon',
'search_api_pantheon_admin',
+ 'search_api_solr_admin'
)
->run();
$this->taskExec(static::$TERMINUS_EXE)
@@ -802,9 +807,41 @@ public function testSolrIndexCreate(string $site_name, string $env = 'dev') {
if (!$result->wasSuccessful()) {
exit(1);
}
+ }
+ public function testPantheonSolrReload(string $site_name, string $env = 'dev') {
+ $result = $this->taskExec( static::$TERMINUS_EXE )
+ ->args(
+ 'drush',
+ "$site_name.$env",
+ '--',
+ 'search-api-pantheon:reloadSchema',
+ )
+ ->run();
+ if (!$result->wasSuccessful()) {
+ exit(1);
+ }
}
+ public function testSolrReload(string $site_name, string $env = 'dev') {
+ $result = $this->taskExec( static::$TERMINUS_EXE )
+ ->args(
+ 'drush',
+ "$site_name.$env",
+ '--',
+ 'search-api-solr:reload',
+ 'pantheon_solr8'
+ )
+ ->run();
+ if (!$result->wasSuccessful()) {
+ exit(1);
+ }
+ }
+
+
+
+
+
/**
* Use search-api-pantheon:select command to ensure both Drupal index and the actual Solr index have the same amount of items.
*
diff --git a/drush.services.yml b/drush.services.yml
index 57fe20ed..2be3d265 100644
--- a/drush.services.yml
+++ b/drush.services.yml
@@ -19,3 +19,8 @@ services:
arguments: [ "@logger.factory", "@search_api_pantheon.pantheon_guzzle", "@search_api_pantheon.endpoint", "@search_api_pantheon.solarium_client" ]
tags:
- { name: drush.command }
+ search_api_pantheon.drush_reload:
+ class: \Drupal\search_api_pantheon\Commands\Reload
+ arguments: [ "@logger.factory", "@search_api_pantheon.pantheon_guzzle", "@search_api_pantheon.schema_poster" ]
+ tags:
+ - { name: drush.command }
diff --git a/phpunit.xml b/phpunit.xml
index 5184585e..b0e49b9c 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -11,6 +11,7 @@
+
diff --git a/search_api_pantheon.module b/search_api_pantheon.module
index fca6766c..1848de5d 100644
--- a/search_api_pantheon.module
+++ b/search_api_pantheon.module
@@ -3,3 +3,16 @@
/**
* @file
*/
+
+function search_api_pantheon_form_alter(&$form, &$form_state, $form_id) {
+ if ($form_id == 'solr_reload_core_form') {
+ $form['#submit'][] = 'search_api_pantheon_form_submit';
+ }
+}
+
+function search_api_pantheon_form_submit($form, &$form_state) {
+ $rl = \Drupal::service("search_api_pantheon.reload");
+ $rl->reloadServer() ?
+ drupal_set_message(t('Core reloaded successfully.')) :
+ drupal_set_message(t('Core reload failed.'), 'error');
+}
diff --git a/search_api_pantheon.services.yml b/search_api_pantheon.services.yml
index f20aa923..8c5a19f1 100755
--- a/search_api_pantheon.services.yml
+++ b/search_api_pantheon.services.yml
@@ -15,3 +15,6 @@ services:
class: Drupal\search_api_pantheon\EventSubscriber\SearchApiPantheonSolrConfigFilesAlter
tags:
- { name: event_subscriber }
+ search_api_pantheon.reload:
+ class: Drupal\search_api_pantheon\Services\Reload
+ arguments: ['@logger.factory', '@search_api_pantheon.pantheon_guzzle']
diff --git a/src/Commands/Diagnose.php b/src/Commands/Diagnose.php
index 066f24fa..1ec37214 100644
--- a/src/Commands/Diagnose.php
+++ b/src/Commands/Diagnose.php
@@ -119,6 +119,9 @@ public function diagnose() {
$this->logger->notice('Index PATH Value: {var}', [
'var' => $this->endpoint->getPath(),
]);
+ $this->logger->notice('Index RELOAD_PATH Value: {var}', [
+ 'var' => $this->endpoint->getReloadPath(),
+ ]);
$this->logger->notice('Testing bare Connection...');
$response = $this->pingSolrHost();
$this->logger->notice('Ping Received Response? {var}', [
diff --git a/src/Commands/Reload.php b/src/Commands/Reload.php
new file mode 100644
index 00000000..9b42b482
--- /dev/null
+++ b/src/Commands/Reload.php
@@ -0,0 +1,68 @@
+logger = $loggerChannelFactory->get('SearchAPIPantheon Drush');
+ $this->pantheonGuzzle = $pantheonGuzzle;
+ $this->schemaPoster = $schemaPoster;
+ }
+
+ /**
+ * Search_api_pantheon:reloadSchema.
+ *
+ * @usage search-api-pantheon:reloadSchema
+ * Reload the latest schema
+ *
+ * @command search-api-pantheon:reloadSchema
+ */
+ public function reloadSchema() {
+ try {
+ $this->schemaPoster->reloadServer();
+ }
+ catch (\Exception $e) {
+ $this->logger->error((string) $e);
+ }
+ }
+
+}
diff --git a/src/Plugin/SolrConnector/PantheonSolrConnector.php b/src/Plugin/SolrConnector/PantheonSolrConnector.php
index c2ce5ea2..591c81ba 100644
--- a/src/Plugin/SolrConnector/PantheonSolrConnector.php
+++ b/src/Plugin/SolrConnector/PantheonSolrConnector.php
@@ -13,9 +13,8 @@
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\search_api_pantheon\Services\PantheonGuzzle;
use Drupal\search_api_pantheon\Services\SolariumClient as PantheonSolariumClient;
-use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
-use Drupal\Core\Messenger\MessengerInterface;
+use Drupal\search_api_pantheon\Services\Reload;
/**
* Pantheon Solr connector.
@@ -64,27 +63,29 @@ class PantheonSolrConnector extends SolrConnectorPluginBase implements
*/
protected $messenger;
+ /**
+ * The container.
+ *
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ protected ContainerInterface $container;
+
/**
* Class constructor.
*/
public function __construct(
- array $configuration,
- $plugin_id,
- array $plugin_definition,
- LoggerChannelFactoryInterface $logger_factory,
- PantheonGuzzle $pantheon_guzzle,
- PantheonSolariumClient $solarium_client,
- DateFormatterInterface $date_formatter,
- MessengerInterface $messenger
+ array $configuration,
+ $plugin_id,
+ array $plugin_definition,
+ ContainerInterface $container,
) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
- $this->pantheonGuzzle = $pantheon_guzzle;
- $this->solariumClient = $solarium_client;
- $this->dateFormatter = $date_formatter;
- $this->messenger = $messenger;
- $this->setLogger($logger_factory->get('PantheonSearch'));
- $this->configuration['core'] = self::getPlatformConfig()['core'];
- $this->configuration['schema'] = self::getPlatformConfig()['schema'];
+ parent::__construct(array_merge($configuration, self::getPlatformConfig()), $plugin_id, $plugin_definition);
+ $this->pantheonGuzzle = $container->get('search_api_pantheon.pantheon_guzzle');
+ $this->solariumClient = $container->get('search_api_pantheon.solarium_client');
+ $this->dateFormatter = $container->get('date.formatter');
+ $this->messenger = $container->get('messenger');
+ $this->setLogger($container->get('logger.factory')->get('PantheonSearch'));
+ $this->container = $container;
$this->connect();
}
@@ -98,21 +99,17 @@ public function __construct(
* @throws \Exception
*/
public static function create(
- ContainerInterface $container,
- array $configuration,
- $plugin_id,
- $plugin_definition
- ) {
+ ContainerInterface $container,
+ array $configuration,
+ $plugin_id,
+ $plugin_definition
+ ) {
return new static(
- $configuration,
- $plugin_id,
- $plugin_definition,
- $container->get('logger.factory'),
- $container->get('search_api_pantheon.pantheon_guzzle'),
- $container->get('search_api_pantheon.solarium_client'),
- $container->get('date.formatter'),
- $container->get('messenger')
- );
+ $configuration,
+ $plugin_id,
+ $plugin_definition,
+ $container,
+ );
}
/**
@@ -129,6 +126,7 @@ public static function getPlatformConfig() {
'path' => getenv('PANTHEON_INDEX_PATH'),
'core' => getenv('PANTHEON_INDEX_CORE'),
'schema' => getenv('PANTHEON_INDEX_SCHEMA'),
+ 'reload_path' => getenv('PANTHEON_INDEX_RELOAD_PATH'),
];
}
@@ -170,9 +168,9 @@ public function defaultConfiguration() {
* Form render array.
*/
public function buildConfigurationForm(
- array $form,
- FormStateInterface $form_state
- ) {
+ array $form,
+ FormStateInterface $form_state
+ ) {
$form = parent::buildConfigurationForm($form, $form_state);
$fields = [
@@ -208,9 +206,9 @@ function ($field_name) use ($fields) {
* Form state object.
*/
public function validateConfigurationForm(
- array &$form,
- FormStateInterface $form_state
- ) {
+ array &$form,
+ FormStateInterface $form_state
+ ) {
}
/**
@@ -222,17 +220,13 @@ public function validateConfigurationForm(
* Form state object.
*/
public function submitConfigurationForm(
- array &$form,
- FormStateInterface $form_state
- ) {
+ array &$form,
+ FormStateInterface $form_state
+ ) {
$configuration = array_merge($this->defaultConfiguration(), $form_state->getValues());
$this->setConfiguration($configuration);
- // Exclude Platform configs.
- foreach (array_keys(self::getPlatformConfig()) as $key) {
- unset($this->configuration[$key]);
- }
}
/**
@@ -293,16 +287,16 @@ public function getStatsSummary() {
}
$summary = [
- '@pending_docs' => '',
- '@autocommit_time_seconds' => '',
- '@autocommit_time' => '',
- '@deletes_by_id' => '',
- '@deletes_by_query' => '',
- '@deletes_total' => '',
- '@schema_version' => '',
- '@core_name' => '',
- '@index_size' => '',
- ];
+ '@pending_docs' => '',
+ '@autocommit_time_seconds' => '',
+ '@autocommit_time' => '',
+ '@deletes_by_id' => '',
+ '@deletes_by_query' => '',
+ '@deletes_total' => '',
+ '@schema_version' => '',
+ '@core_name' => '',
+ '@index_size' => '',
+ ];
if (empty($stats) || empty($indexStats)) {
return $summary;
@@ -311,33 +305,33 @@ public function getStatsSummary() {
$max_time = -1;
$update_handler_stats = $stats['UPDATE']['updateHandler']['stats'] ?? -1;
$summary['@pending_docs'] =
- (int) $update_handler_stats['UPDATE.updateHandler.docsPending'] ?? -1;
+ (int) $update_handler_stats['UPDATE.updateHandler.docsPending'] ?? -1;
if (
- isset(
- $update_handler_stats['UPDATE.updateHandler.softAutoCommitMaxTime']
- )
- ) {
+ isset(
+ $update_handler_stats['UPDATE.updateHandler.softAutoCommitMaxTime']
+ )
+ ) {
$max_time =
- (int) $update_handler_stats['UPDATE.updateHandler.softAutoCommitMaxTime'];
+ (int) $update_handler_stats['UPDATE.updateHandler.softAutoCommitMaxTime'];
}
$summary['@deletes_by_id'] =
- (int) $update_handler_stats['UPDATE.updateHandler.deletesById'] ?? -1;
+ (int) $update_handler_stats['UPDATE.updateHandler.deletesById'] ?? -1;
$summary['@deletes_by_query'] =
- (int) $update_handler_stats['UPDATE.updateHandler.deletesByQuery'] ?? -1;
+ (int) $update_handler_stats['UPDATE.updateHandler.deletesByQuery'] ?? -1;
$summary['@core_name'] =
- $stats['CORE']['core']['class'] ??
- $this->t('No information available.');
+ $stats['CORE']['core']['class'] ??
+ $this->t('No information available.');
$summary['@index_size'] =
- $indexStats['numDocs'] ?? $this->t('No information available.');
+ $indexStats['numDocs'] ?? $this->t('No information available.');
$summary['@autocommit_time_seconds'] = $max_time / 1000;
$summary['@autocommit_time'] = $this->dateFormatter
->formatInterval($max_time / 1000);
$summary['@deletes_total'] =
- (
- intval($summary['@deletes_by_id'] ?? 0)
- + intval($summary['@deletes_by_query'] ?? 0)
- ) ?? -1;
+ (
+ intval($summary['@deletes_by_id'] ?? 0)
+ + intval($summary['@deletes_by_query'] ?? 0)
+ ) ?? -1;
$summary['@schema_version'] = $this->getSchemaVersionString(TRUE);
return $summary;
}
@@ -346,9 +340,9 @@ public function getStatsSummary() {
* {@inheritdoc}
*/
public function useTimeout(
- string $timeout = self::QUERY_TIMEOUT,
- ?Endpoint $endpoint = NULL
- ) {
+ string $timeout = self::QUERY_TIMEOUT,
+ ?Endpoint $endpoint = NULL
+ ) {
}
/**
@@ -360,25 +354,25 @@ public function viewSettings() {
$view_settings = [];
$view_settings[] = [
- 'label' => $this->t('Pantheon Sitename'),
- 'info' => $this->getEndpoint()->getCore(),
- ];
+ 'label' => $this->t('Pantheon Sitename'),
+ 'info' => $this->getEndpoint()->getCore(),
+ ];
$view_settings[] = [
- 'label' => $this->t('Pantheon Environment'),
- 'info' => getenv('PANTHEON_ENVIRONMENT'),
- ];
+ 'label' => $this->t('Pantheon Environment'),
+ 'info' => getenv('PANTHEON_ENVIRONMENT'),
+ ];
$view_settings[] = [
- 'label' => $this->t('Schema Version'),
- 'info' => $this->getSchemaVersion(TRUE),
- ];
+ 'label' => $this->t('Schema Version'),
+ 'info' => $this->getSchemaVersion(TRUE),
+ ];
$core_info = $this->getCoreInfo(TRUE);
foreach ($core_info['core'] as $key => $value) {
if (is_string($value)) {
$view_settings[] = [
- 'label' => ucwords($key),
- 'info' => $value,
- ];
+ 'label' => ucwords($key),
+ 'info' => $value,
+ ];
}
}
@@ -404,11 +398,9 @@ public function getEndpoint($key = 'search_api_solr') {
* @return bool
* Success or Failure.
*/
- public function reloadCore() {
- $this->logger->notice(
- $this->t('Reload Core action for Pantheon Solr is automatic when Schema is updated.')
- );
- return TRUE;
+ public function reloadCore(): bool {
+ $rl = new Reload($this->container->get("logger.factory"), $this->pantheonGuzzle);
+ return $rl->reloadServer();
}
/**
@@ -462,29 +454,29 @@ protected function createClient(array &$configuration) {
*/
protected function getStatsQuery(string $handler) {
return json_decode(
- $this->pantheonGuzzle
- ->get(
- $handler,
- [
- 'query' =>
- [
- 'stats' => 'true',
- 'wt' => 'json',
- 'accept' => 'application/json',
- 'contenttype' => 'application/json',
- 'json.nl' => 'flat',
- ],
- 'headers' =>
- [
- 'Content-Type' => 'application/json',
- 'Accept' => 'application/json',
- ],
- ]
- )
- ->getBody(),
- TRUE,
- JSON_THROW_ON_ERROR
- );
+ $this->pantheonGuzzle
+ ->get(
+ $handler,
+ [
+ 'query' =>
+ [
+ 'stats' => 'true',
+ 'wt' => 'json',
+ 'accept' => 'application/json',
+ 'contenttype' => 'application/json',
+ 'json.nl' => 'flat',
+ ],
+ 'headers' =>
+ [
+ 'Content-Type' => 'application/json',
+ 'Accept' => 'application/json',
+ ],
+ ]
+ )
+ ->getBody(),
+ TRUE,
+ JSON_THROW_ON_ERROR
+ );
}
}
diff --git a/src/Services/Endpoint.php b/src/Services/Endpoint.php
index 7b9cf98f..7a5f93a8 100644
--- a/src/Services/Endpoint.php
+++ b/src/Services/Endpoint.php
@@ -198,6 +198,35 @@ public function getSchemaUploadUri(): string {
);
}
+ /**
+ * Get URL in pantheon environment to POST reload requests.
+ *
+ * @return string
+ * URL of envrionment.
+ */
+ public function getReloadUri(): string {
+ return vsprintf(
+ '%s://%s:%d/%s%s',
+ [
+ $this->getScheme(),
+ $this->getHost(),
+ $this->getPort(),
+ $this->getPath(),
+ $this->getReloadPath(),
+ ]
+ );
+ }
+
+ /**
+ * Get the path for Schema Reloads.
+ *
+ * @return string
+ * The path for schema reloads
+ */
+ public function getReloadPath(): string {
+ return $this->options['reload_path'];
+ }
+
/**
* Get the path for Schema Uploads.
*
diff --git a/src/Services/PantheonGuzzle.php b/src/Services/PantheonGuzzle.php
index 89ff0cf0..55e9b256 100644
--- a/src/Services/PantheonGuzzle.php
+++ b/src/Services/PantheonGuzzle.php
@@ -73,8 +73,14 @@ public function __construct(Endpoint $endpoint, LoggerChannelFactoryInterface $l
$config['cert'] = $cert;
}
parent::__construct($config);
- $this->endpoint = $endpoint;
- $this->logger = $logger_factory->get('PantheonGuzzle');
+ if (!$endpoint instanceof Endpoint) {
+ throw new \InvalidArgumentException('Endpoint must be an instance of Endpoint');
+ }
+ $this->setEndpoint($endpoint);
+ if ($logger_factory instanceof LoggerChannelFactoryInterface) {
+ $this->setLogger($logger_factory->get('PantheonGuzzle'));
+ }
+ $this->setLogger($logger_factory->get('PantheonGuzzle'));
}
/**
diff --git a/src/Services/Reload.php b/src/Services/Reload.php
new file mode 100644
index 00000000..4de21a26
--- /dev/null
+++ b/src/Services/Reload.php
@@ -0,0 +1,82 @@
+setLogger($logger_factory->get('reload_service'));
+ $this->client = $client;
+ }
+
+ /**
+ * Reload the server after schema upload.
+ *
+ * @throws \Drupal\search_api_pantheon\Exceptions\PantheonSearchApiException
+ */
+ public function reloadServer(): bool {
+ // Schema upload URL.
+ $uri = new Uri(
+ $this->getClient()
+ ->getEndpoint()
+ ->getReloadUri()
+ );
+
+ $this->logger->debug('Reload url: ' . (string) $uri);
+
+ // Send the request.
+ $request = new Request(
+ 'POST',
+ $uri,
+ [
+ 'Accept' => 'application/json',
+ 'Content-Type' => 'application/json',
+ ]
+ );
+ $response = $this->getClient()->sendRequest($request);
+
+ $status_code = $response->getStatusCode();
+ $reload_logger_content = [
+ 'status_code' => $status_code,
+ 'reason' => $response->getReasonPhrase(),
+ ];
+ if ($status_code >= 200 && $status_code < 300) {
+ $this->logger->info('Server reloaded: {status_code} {reason}', $reload_logger_content);
+ return TRUE;
+ }
+ $this->logger->error('Server not reloaded: {status_code} {reason}', $reload_logger_content);
+ return FALSE;
+ }
+
+ public function getClient(): PantheonGuzzle {
+ return $this->client;
+ }
+
+}
diff --git a/src/Services/SchemaPoster.php b/src/Services/SchemaPoster.php
index fac2c2f6..bd2ba9b4 100644
--- a/src/Services/SchemaPoster.php
+++ b/src/Services/SchemaPoster.php
@@ -58,6 +58,8 @@ class SchemaPoster implements LoggerAwareInterface {
*/
protected $moduleExtensionList;
+ protected LoggerChannelFactoryInterface $loggerFactory;
+
/**
* Class Constructor.
*/
@@ -68,6 +70,7 @@ public function __construct(
ModuleExtensionList $module_extension_list
) {
$this->logger = $logger_factory->get('PantheonSearch');
+ $this->loggerFactory = $logger_factory;
$this->client = $client;
$this->entityTypeManager = $entity_type_manager;
$this->moduleExtensionList = $module_extension_list;
@@ -105,9 +108,27 @@ public function postSchema(string $server_id, $files = []): array {
throw new \Exception('Cannot post schema to environment url.');
}
+ $status_code = $response->getStatusCode();
+ $this->logger->info('Status code: ' . $status_code);
+ if ($status_code >= 200 && $status_code < 300) {
+ // Call reload on the server.
+ $this->reloadServer();
+ }
return $this->processResponse($response);
}
+ /**
+ * Reload the server after schema upload.
+ *
+ * @throws \Drupal\search_api_pantheon\Exceptions\PantheonSearchApiException
+ *
+ * @return bool
+ */
+ public function reloadServer(): bool {
+ $reload = new Reload($this->loggerFactory, $this->client);
+ return $reload->reloadServer();
+ }
+
/**
* Process response and return message to be shown to user.
*
diff --git a/tests/Unit/EndpointServiceTest.php b/tests/Unit/EndpointServiceTest.php
index a37d8dd2..8792fda1 100644
--- a/tests/Unit/EndpointServiceTest.php
+++ b/tests/Unit/EndpointServiceTest.php
@@ -28,6 +28,7 @@ public function testURIGeneration() {
'schema' => '/schema-path',
'collection' => NULL,
'leader' => FALSE,
+ 'reload_path' => "/reload-path",
]);
$this->assertEquals('/core-name', $ep->getCore());
@@ -43,6 +44,15 @@ public function testURIGeneration() {
'one://two:1234/server-path/schema-path',
$ep->getSchemaUploadUri()
);
+ $this->assertEquals(
+ 'one://two:1234/server-path/reload-path',
+ $ep->getReloadUri()
+ );
+ }
+
+ public function testReloadPath() {
+ $ep = new Endpoint(["reload_path" => "/reload"]);
+ $this->assertEquals("/reload", $ep->getReloadPath());
}
}
diff --git a/tests/Unit/GuzzleClassTest.php b/tests/Unit/GuzzleClassTest.php
index d873e0d8..1e08b746 100644
--- a/tests/Unit/GuzzleClassTest.php
+++ b/tests/Unit/GuzzleClassTest.php
@@ -19,6 +19,8 @@
*/
class GuzzleClassTest extends TestCase {
+ protected $loggerFactory;
+
/**
* {@inheritdoc}
*/