[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/search/engine/solr/classes/ -> schema.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Solr schema manipulation manager.
  19   *
  20   * @package   search_solr
  21   * @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace search_solr;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->dirroot . '/lib/filelib.php');
  30  
  31  /**
  32   * Schema class to interact with Solr schema.
  33   *
  34   * At the moment it only implements create which should be enough for a basic
  35   * moodle configuration in Solr.
  36   *
  37   * @package   search_solr
  38   * @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
  39   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class schema {
  42  
  43      /**
  44       * @var stdClass
  45       */
  46      protected $config = null;
  47  
  48      /**
  49       * cUrl instance.
  50       * @var \curl
  51       */
  52      protected $curl = null;
  53  
  54      /**
  55       * An engine instance.
  56       * @var engine
  57       */
  58      protected $engine = null;
  59  
  60      /**
  61       * Constructor.
  62       *
  63       * @throws \moodle_exception
  64       * @return void
  65       */
  66      public function __construct() {
  67          if (!$this->config = get_config('search_solr')) {
  68              throw new \moodle_exception('missingconfig', 'search_solr');
  69          }
  70  
  71          if (empty($this->config->server_hostname) || empty($this->config->indexname)) {
  72              throw new \moodle_exception('missingconfig', 'search_solr');
  73          }
  74  
  75          $this->engine = new engine();
  76          $this->curl = $this->engine->get_curl_object();
  77  
  78          // HTTP headers.
  79          $this->curl->setHeader('Content-type: application/json');
  80      }
  81  
  82      /**
  83       * Can setup be executed against the configured server.
  84       *
  85       * @return true|string True or error message.
  86       */
  87      public function can_setup_server() {
  88  
  89          $engine = new \search_solr\engine();
  90          $status = $engine->is_server_configured();
  91          if ($status !== true) {
  92              return $status;
  93          }
  94  
  95          // We know that the server is ready here.
  96          if ($engine->get_solr_major_version() < 5) {
  97              // Schema setup script only available for 5.0 onwards.
  98              return get_string('schemasetupfromsolr5', 'search_solr');
  99          }
 100  
 101          return true;
 102      }
 103  
 104      /**
 105       * Setup solr stuff required by moodle.
 106       *
 107       * @param  bool $checkexisting Whether to check if the fields already exist or not
 108       * @return bool
 109       */
 110      public function setup($checkexisting = true) {
 111          $fields = \search_solr\document::get_default_fields_definition();
 112  
 113          // Field id is already there.
 114          unset($fields['id']);
 115  
 116          $this->check_index();
 117  
 118          return $this->add_fields($fields, $checkexisting);
 119      }
 120  
 121      /**
 122       * Checks the schema is properly set up.
 123       *
 124       * @throws \moodle_exception
 125       * @return void
 126       */
 127      public function validate_setup() {
 128          $fields = \search_solr\document::get_default_fields_definition();
 129  
 130          // Field id is already there.
 131          unset($fields['id']);
 132  
 133          $this->check_index();
 134          $this->validate_fields($fields, true);
 135      }
 136  
 137      /**
 138       * Checks if the index is ready, triggers an exception otherwise.
 139       *
 140       * @throws \moodle_exception
 141       * @return void
 142       */
 143      protected function check_index() {
 144  
 145          // Check that the server is available and the index exists.
 146          $url = $this->engine->get_connection_url('/select?wt=json');
 147          $result = $this->curl->get($url);
 148          if ($this->curl->error) {
 149              throw new \moodle_exception('connectionerror', 'search_solr');
 150          }
 151          if ($this->curl->info['http_code'] === 404) {
 152              throw new \moodle_exception('connectionerror', 'search_solr');
 153          }
 154      }
 155  
 156      /**
 157       * Adds the provided fields to Solr schema.
 158       *
 159       * Intentionally separated from create(), it can be called to add extra fields.
 160       * fields separately.
 161       *
 162       * @throws \coding_exception
 163       * @throws \moodle_exception
 164       * @param  array $fields \core_search\document::$requiredfields format
 165       * @param  bool $checkexisting Whether to check if the fields already exist or not
 166       * @return bool
 167       */
 168      protected function add_fields($fields, $checkexisting = true) {
 169  
 170          if ($checkexisting) {
 171              // Check that non of them exists.
 172              $this->validate_fields($fields, false);
 173          }
 174  
 175          $url = $this->engine->get_connection_url('/schema');
 176  
 177          // Add all fields.
 178          foreach ($fields as $fieldname => $data) {
 179  
 180              if (!isset($data['type']) || !isset($data['stored']) || !isset($data['indexed'])) {
 181                  throw new \coding_exception($fieldname . ' does not define all required field params: type, stored and indexed.');
 182              }
 183              // Changing default multiValued value to false as we want to match values easily.
 184              $params = array(
 185                  'add-field' => array(
 186                      'name' => $fieldname,
 187                      'type' => ($data['type'] === 'text' ? 'text_general' : $data['type']),
 188                      'stored' => $data['stored'],
 189                      'multiValued' => false,
 190                      'indexed' => $data['indexed']
 191                  )
 192              );
 193              $results = $this->curl->post($url, json_encode($params));
 194  
 195              // We only validate if we are interested on it.
 196              if ($checkexisting) {
 197                  if ($this->curl->error) {
 198                      throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $this->curl->error);
 199                  }
 200                  $this->validate_add_field_result($results);
 201              }
 202          }
 203  
 204          return true;
 205      }
 206  
 207      /**
 208       * Checks if the schema existing fields are properly set, triggers an exception otherwise.
 209       *
 210       * @throws \moodle_exception
 211       * @param array $fields
 212       * @param bool $requireexisting Require the fields to exist, otherwise exception.
 213       * @return void
 214       */
 215      protected function validate_fields(&$fields, $requireexisting = false) {
 216          global $CFG;
 217  
 218          foreach ($fields as $fieldname => $data) {
 219              $url = $this->engine->get_connection_url('/schema/fields/' . $fieldname);
 220              $results = $this->curl->get($url);
 221  
 222              if ($this->curl->error) {
 223                  throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $this->curl->error);
 224              }
 225  
 226              if (!$results) {
 227                  throw new \moodle_exception('errorcreatingschema', 'search_solr', '', get_string('nodatafromserver', 'search_solr'));
 228              }
 229              $results = json_decode($results);
 230  
 231              if ($requireexisting && !empty($results->error) && $results->error->code === 404) {
 232                  $a = new \stdClass();
 233                  $a->fieldname = $fieldname;
 234                  $a->setupurl = $CFG->wwwroot . '/search/engine/solr/setup_schema.php';
 235                  throw new \moodle_exception('errorvalidatingschema', 'search_solr', '', $a);
 236              }
 237  
 238              // The field should not exist so we only accept 404 errors.
 239              if (empty($results->error) || (!empty($results->error) && $results->error->code !== 404)) {
 240                  if (!empty($results->error)) {
 241                      throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $results->error->msg);
 242                  } else {
 243                      // All these field attributes are set when fields are added through this script and should
 244                      // be returned and match the defined field's values.
 245  
 246                      if (empty($results->field) || !isset($results->field->type) ||
 247                              !isset($results->field->multiValued) || !isset($results->field->indexed) ||
 248                              !isset($results->field->stored)) {
 249  
 250                          throw new \moodle_exception('errorcreatingschema', 'search_solr', '',
 251                              get_string('schemafieldautocreated', 'search_solr', $fieldname));
 252  
 253                      } else if (($results->field->type !== $data['type'] &&
 254                                  ($data['type'] !== 'text' || $results->field->type !== 'text_general')) ||
 255                                  $results->field->multiValued !== false ||
 256                                  $results->field->indexed !== $data['indexed'] ||
 257                                  $results->field->stored !== $data['stored']) {
 258  
 259                              throw new \moodle_exception('errorcreatingschema', 'search_solr', '',
 260                                  get_string('schemafieldautocreated', 'search_solr', $fieldname));
 261                      } else {
 262                          // The field already exists and it is properly defined, no need to create it.
 263                          unset($fields[$fieldname]);
 264                      }
 265                  }
 266              }
 267          }
 268      }
 269  
 270      /**
 271       * Checks that the field results do not contain errors.
 272       *
 273       * @throws \moodle_exception
 274       * @param string $results curl response body
 275       * @return void
 276       */
 277      protected function validate_add_field_result($result) {
 278  
 279          if (!$result) {
 280              throw new \moodle_exception('errorcreatingschema', 'search_solr', '', get_string('nodatafromserver', 'search_solr'));
 281          }
 282  
 283          $results = json_decode($result);
 284          if (!$results) {
 285              if (is_scalar($result)) {
 286                  $errormsg = $result;
 287              } else {
 288                  $errormsg = json_encode($result);
 289              }
 290              throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $errormsg);
 291          }
 292  
 293          // It comes as error when fetching fields data.
 294          if (!empty($results->error)) {
 295              throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $results->error);
 296          }
 297  
 298          // It comes as errors when adding fields.
 299          if (!empty($results->errors)) {
 300  
 301              // We treat this error separately.
 302              $errorstr = '';
 303              foreach ($results->errors as $error) {
 304                  $errorstr .= implode(', ', $error->errorMessages);
 305              }
 306              throw new \moodle_exception('errorcreatingschema', 'search_solr', '', $errorstr);
 307          }
 308  
 309      }
 310  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1