Skip to content

Commit

Permalink
Issue: #53: add pantheon_apachesolr (#59).
Browse files Browse the repository at this point in the history
Adds pantheon_apachesolr module and moves pantheon_api module. Be sure to clear all caches.
  • Loading branch information
herbdool authored Apr 2, 2022
1 parent 83ab755 commit 43b40be
Show file tree
Hide file tree
Showing 8 changed files with 1,158 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
<?php

/**
* Current Supported Class for RC4+
*/
class PantheonApachesolrSearchApiSolrConnection extends SearchApiSolrConnection {

function __construct(array $options) {

// Adding in custom settings for Pantheon
$options['scheme'] = 'https';
$options['host'] = settings_get('pantheon_index_host', 'index.'. settings_get('pantheon_tier', 'live') .'.getpantheon.com');
$options['path'] = 'sites/self/environments/' . settings_get('pantheon_environment', 'dev') . '/index';
$options['port'] = settings_get('pantheon_index_port', 449);
$this->setStreamContext(
stream_context_create(
array(
'ssl' => array(
'local_cert' => pantheon_apachesolr_client_cert(),
)
)
)
);

// Adding in general settings for Search API
$options += array(
'scheme' => 'http',
'host' => 'localhost',
'port' => 8983,
'path' => 'solr',
'http_user' => NULL,
'http_pass' => NULL,
'http_method' => 'POST',
'local_cert'=> NULL,
);
$this->options = $options;

$path = '/' . trim($options['path'], '/') . '/';
$this->base_url = $options['scheme'] . '://' . $options['host'] . ':' . $options['port'] . $path;

// Make sure we always have a valid method set, default to POST.
$this->method = $options['http_method'] == 'GET' ? 'GET' : 'POST';

// Set HTTP Basic Authentication parameter, if login data was set.
if (strlen($options['http_user']) && strlen($options['http_pass'])) {
$this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']);
}
}

/**
* Sends an HTTP request to Solr.
*
* This is just a wrapper around backdrop_http_request().
*
* Overridden by Pantheon to set a timeout and possibly other improvements.
*/
protected function makeHttpRequest($url, array $options = array()) {
if (empty($options['method']) || $options['method'] == 'GET' || $options['method'] == 'HEAD') {
// Make sure we are not sending a request body.
$options['data'] = NULL;
}
if ($this->http_auth) {
$options['headers']['Authorization'] = $this->http_auth;
}
if ($this->stream_context) {
$options['context'] = $this->stream_context;
}
// Specify timeout.
$options['timeout'] = 5;

$result = backdrop_http_request($url, $options);

if (!isset($result->code) || $result->code < 0) {
$result->code = 0;
$result->status_message = 'Request failed';
$result->protocol = 'HTTP/1.0';
}
// Additional information may be in the error property.
if (isset($result->error)) {
$result->status_message .= ': ' . check_plain($result->error);
}

if (!isset($result->data)) {
$result->data = '';
$result->response = NULL;
}
else {
$response = json_decode($result->data);
if (is_object($response)) {
foreach ($response as $key => $value) {
$result->$key = $value;
}
}
}

return $result;
}

}

class PantheonApachesolrSearchApiSolrService extends SearchApiSolrService {
protected $connection_class = 'PantheonApachesolrSearchApiSolrConnection';
}

/**
* Legacy Supported Class for RC2
*/
class PantheonSearchApiSolrService extends SearchApiSolrConnection {
/**
* Constructor
*/
public function __construct(array $options) {
$host = settings_get('pantheon_index_host', 'index.'. settings_get('pantheon_tier', 'live') .'.getpantheon.com');
$path = 'sites/self/environments/'. settings_get('pantheon_environment', 'dev') .'/index';
$options = array(
'host' => $host,
'path' => $path,
'port' => 449,
'default_field' => 'id',
);
parent::__construct($options);
// Since /ping otherwise complains about missing default field.
$this->_pingUrl .= '?q=' . $options['default_field'] . ':1';

// As of July 2011, the newest release is r60, with Service.php having
// revision 59. Revision 40 is just anything between 22 (old) and that.
$this->newClient = trim(parent::SVN_REVISION, '$ :A..Za..z') > 40;
if ($this->newClient) {
$this->_httpTransport = new PanteheonSearchApiSolrHttpTransport();
}
}
}

/**
* Pantheon implementation of the HTTP transport interface.
*
* Uses curl() for sending the request with certificate auth
*/

if (class_exists('Apache_Solr_HttpTransport_Abstract')) {
class PanteheonSearchApiSolrHttpTransport extends Apache_Solr_HttpTransport_Abstract {
public function __construct() {}

/**
* Perform a GET HTTP operation with an optional timeout and return the response
* contents, use getLastResponseHeaders to retrieve HTTP headers
*
* @param string $url
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performGetRequest($url, $timeout = FALSE) {
return $this->performHttpRequest('GET', $url, $timeout);
}

/**
* Perform a HEAD HTTP operation with an optional timeout and return the response
* headers - NOTE: head requests have no response body
*
* @param string $url
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performHeadRequest($url, $timeout = FALSE) {
return $this->performHttpRequest('HEAD', $url, $timeout);
}

/**
* Perform a POST HTTP operation with an optional timeout and return the response
* contents, use getLastResponseHeaders to retrieve HTTP headers
*
* @param string $url
* @param string $rawPost
* @param string $contentType
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performPostRequest($url, $rawPost, $contentType, $timeout = FALSE) {
return $this->performHttpRequest('POST', $url, $timeout, $rawPost, $contentType);
}

/**
* Helper method for making an HTTP request.
*/
protected function performHttpRequest($method, $url, $timeout, $rawPost = NULL, $contentType = NULL) {
// The _constructUrl() in Apache_Solr_Service hard codes http like a boss.
$url = str_replace('http://', 'https://', $url);
// Kludgy workaround of double-get-arging.
// https://index.live.getpantheon.com:449/sites/self/environments/dev/index/admin/ping?q=id:1?q=id:1
// WHY ARG WHY!?!?!
$parts = explode('?', $url);
$url = $parts[0] .'?'. $parts[1];
$client_cert = pantheon_apachesolr_client_cert();
$port = settings_get('pantheon_index_port', 449);
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSLCERT, $client_cert);

$opts = pantheon_apachesolr_curlopts();
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_PORT] = $port;

if ($timeout) {
$opts[CURLOPT_CONNECTTIMEOUT] = $timeout;
}
curl_setopt_array($ch, $opts);

// If we are doing a delete request...
if ($method == 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
}
// If we are doing a put request...
if ($method == 'PUT') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
}
// If we are doing a put request...
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, 1);
}
if ($rawPost) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $rawPost);
}

$response = curl_exec($ch);

if ($response == NULL) {
// TODO; better error handling.
watchdog('pantheon_apachesolr', "Error !error connecting to !url on port !port", array('!error' => curl_error($ch), '!url' => $url, '!port' => $port), WATCHDOG_ERROR);
}
else {
// mimick the $result object from backdrop_http_request()
// TODO; better error handling
$result = new stdClass();
list($split, $result->data) = explode("\r\n\r\n", $response, 2);
$split = preg_split("/\r\n|\n|\r/", $split);
list($result->protocol, $result->code, $result->status_message) = explode(' ', trim(array_shift($split)), 3);
// Parse headers.
$result->headers = array();
while ($line = trim(array_shift($split))) {
list($header, $value) = explode(':', $line, 2);
if (isset($result->headers[$header]) && $result->header == 'Set-Cookie') {
// RFC 2109: the Set-Cookie response header comprises the token Set-
// Cookie:, followed by a comma-separated list of one or more cookies.
$result->headers[$header] .= ',' . trim($value);
}
else {
$result->headers[$header] = trim($value);
}
}
}

if (!isset($result->code) || $result->code < 0) {
$result->code = 0;
$result->status_message = 'Request failed';
$result->protocol = 'HTTP/1.0';
}
// Additional information may be in the error property.
if (isset($result->error)) {
$result->status_message .= ': ' . check_plain($result->error);
}

if (!isset($result->data)) {
$result->data = '';
$result->response = NULL;
}
else {
$response = json_decode($result->data);
if (is_object($response)) {
foreach ($response as $key => $value) {
$result->$key = $value;
}
}
}

// backdrop_set_message("$url: $result->code");

$type = isset($result->headers['content-type']) ? $result->headers['content-type'] : 'text/xml';
$body = isset($result->data) ? $result->data : NULL;
return new Apache_Solr_HttpTransport_Response($result->code, $type, $body);
}

}
}
40 changes: 40 additions & 0 deletions core/modules/pantheon/pantheon_apachesolr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Pantheon Apache Solr
====================

[Apache Solr](http://lucene.apache.org/solr/) is a system that exposes APIs for indexing and searching site content. Pantheon provides a regular Solr v3.x server for each environment as a service.

Installation
------------

For each Pantheon environment (dev, test and live), post the desired schema.xml to the Apache Solr server using the [post schema](admin/config/search/pantheon/schema) interface. Step-by-step instructions can be found in [Apache Solr on Pantheon](https://www.getpantheon.com/docs/articles/sites/apache-solr/).

Compatibility
-------------

The pantheon_apachesolr module was optimized for use with [Search API Solr search v7.x-1.2](https://drupal.org/project/search_api_solr).

Prior and development versions are not supported or recommended. Future versions should work; if you encounter a problem with a newer official release, please notify Pantheon Support.

Vocabulary
----------

* bias
Allows certain parts of indexed items to influence the importance of search results. The higher the bias, the greater the influence; the range is 0.1 to 21.0.
* core
A core is a separate configuration and index using a single Solr instance. A core is created when the schema is posted. For more information, see <http://wiki.apache.org/solr/CoreAdmin>.
* document
A document is similar to a database row, containing the contents of what is to be searched and whatever fields are associated with it, like title
* facet
Search facets allow search results to be filtered; examples include seeing a list of potential filters and the count of matches for each filter on the left, like Amazon product searches.
* index
structure containing extracted keywords from a document for rapid search and retrieval, similar to a database table.
* score
calculated relevance of matches influenced by bias, represented as a float.
* schema.xml
Contains details about the fields that documents can contain, and how those fields are handled when adding documents to the index or querying those fields. Must be posted using the pantheon_apachesolr module before indexing and searching will work. For more information, see <http://wiki.apache.org/solr/SchemaXml>.

Known Limitations
-----------------

* Anything that takes more than 5 seconds to send to to the Solr server be indexed will timeout, which will block indexing. For example, large documents attached to Drupal nodes. In these cases, the developer must work with the content or code to exempt the nodes and/or files from being indexed.
* solrconfig.xml and synonyms.txt cannot be modified.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"_config_name": "pantheon_apachesolr.settings",
"pantheon_apachesolr_schema": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name = Pantheon Apache Solr
description = Exposes Pantheon's ApacheSolr Service
package = Pantheon
version = "1.x-1.0"
configure = admin/config/search/pantheon
backdrop = 1.x
type = module
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/**
* Install/Update hooks for solr.
*/

/**
* Implements hook_update_last_removed().
*/
function pantheon_apachesolr_update_last_removed() {
return 7003;
}

/**
* Move Pantheon Apache Solr settings from variables to config.
*/
function pantheon_apachesolr_update_1000() {
// Migrate variables to config.
$config = config('pantheon_apachesolr.settings');
$config->set('pantheon_apachesolr_schema', update_variable_get('pantheon_apachesolr_schema', ''));
$config->save();

// Delete variables.
update_variable_del('pantheon_apachesolr_schema');
}
Loading

0 comments on commit 43b40be

Please sign in to comment.