You are here

class SearchApiAlgoliaService in Search API Algolia 7

SearchApiAlgoliaService class.

Hierarchy

Expanded class hierarchy of SearchApiAlgoliaService

1 string reference to 'SearchApiAlgoliaService'
search_api_algolia_search_api_service_info in ./search_api_algolia.module
Implements hook_info().

File

includes/service.inc, line 11
Contains SearchApiAlgoliaService.

View source
class SearchApiAlgoliaService extends SearchApiAbstractService {
  protected $algoliaIndex = NULL;

  /**
   * Get the Algolia index.
   */
  protected function getAlgoliaIndex() {
    return $this->algoliaIndex;
  }

  /**
   * Set the Algolia index.
   */
  protected function setAlgoliaIndex($index) {
    $this->algoliaIndex = $index;
  }

  /**
   * Connect to the Algolia service.
   *
   * Uses the application ID et API key provided in the UI.
   */
  protected function connect($index) {

    // @todo Make the absence of lib more visible (error message on the status
    // report page for instance, and during the install process).
    if (($library = libraries_load('algolia')) && !empty($library['loaded'])) {
      if (defined('VERSION')) {
        \AlgoliaSearch\Version::addSuffixUserAgentSegment('Drupal', VERSION);
      }
      $version = '';
      if (function_exists($library['version callback'])) {
        $version = call_user_func($library['version callback']);
      }
      \AlgoliaSearch\Version::addSuffixUserAgentSegment('Drupal community module', $version);
      $algolia_client = new \AlgoliaSearch\Client($this
        ->getApplicationID(), $this
        ->getApiKey());
      $this
        ->setAlgoliaIndex($algolia_client
        ->initIndex($index->name));
    }
    else {
      throw new SearchApiException(t('Algolia library could not be found or did not load properly.'));
    }
  }

  /**
   * Get the ApplicationID (provided by Algolia).
   */
  protected function getApplicationId() {
    return $this->options['application_id'];
  }

  /**
   * Get the API key (provided by Algolia).
   */
  protected function getApiKey() {
    return $this->options['api_key'];
  }

  /**
   * Defines the configuration form displayed when creating a new server.
   */
  public function configurationForm(array $form, array &$form_state) {
    $form['application_id'] = array(
      '#type' => 'textfield',
      '#title' => t('Application ID'),
      '#size' => 60,
      '#maxlength' => 128,
      '#required' => TRUE,
      '#default_value' => $this
        ->getApplicationId(),
    );
    $form['api_key'] = array(
      '#type' => 'textfield',
      '#title' => t('API key'),
      '#size' => 60,
      '#maxlength' => 128,
      '#required' => TRUE,
      '#default_value' => $this
        ->getAPIKey(),
    );
    return $form;
  }

  /**
   * Implements viewSettings.
   */
  public function viewSettings() {

    // @todo Write service options (SearchApiAlgoliaService class).
    $output = '';
    return $output;
  }

  /**
   * Implements indexItems.
   *
   * Naming convention:
   * - items
   *   - item
   *     - property
   *       - type
   *       - entity_type
   *       - value : single value or array.
   */
  public function indexItems(SearchApiIndex $index, array $items) {
    $items_to_index = array();
    $items_indexed = array();

    // Retrieving the entity key ('nid' for nodes, 'uid' for users, etc...).
    $entity_key = entity_get_info($index->item_type)['entity keys']['id'];

    // Connect to the Algolia service.
    $this
      ->connect($index);

    // Iterate over all the items ready for indexing.
    foreach ($items as $item) {
      $item_to_index = array();

      // And then iterate over all the properties of these items.
      foreach ($item as $key => $property) {

        // Do not index the property if its value is not set.
        if (isset($property['value'])) {

          // Do not process the entity id at that stage. Its value is indexed
          // separately as it requires a special property name (ObjectID) in
          // order to be indexed by Algolia.
          if ($key != $entity_key) {

            // If the property type is defined as a list and entity_type is set,
            // we are facing a multivalued entity (checking list<integeger> is
            // not enough as this could be used by a standard select, with no
            // reference).
            // @todo Handle multivalued fields which are not entity reference.
            if (preg_match('/^list<[^>]+>/', $property['type']) && isset($property['entity_type'])) {
              $entity_type = $property['entity_type'];
              foreach ($property['value'] as $property_list_value) {
                $wrapper = entity_metadata_wrapper($entity_type, entity_load_single($entity_type, $property_list_value));
                $item_to_index[$key][] = $wrapper
                  ->label();
              }
            }
            else {

              // If entity_type is defined, it means we are facing an entity
              // reference. We then use an entity wrapper to output it.
              if (isset($property['entity_type'])) {
                $entity_type = $property['entity_type'];
                $wrapper = entity_metadata_wrapper($entity_type, entity_load_single($entity_type, $property['value']));
                $property_value = $wrapper
                  ->label();
              }
              else {
                if ($property['type'] == 'integer') {

                  // We need to transtype the content of integer fields (as they
                  // are stored as string) so that Algolia sees them as
                  // integers.
                  // @todo MAYBE: if more types need to be recognized, make
                  // something more scalable here.
                  $property_value = (int) $property['value'];
                }
                else {
                  $property_value = $property['value'];
                }
              }
              $item_to_index[$key] = $property_value;
            }
          }
          else {

            // Match the entity key to the objectID primary key required by
            // Algolia.
            $item_to_index['objectID'] = $item[$entity_key]['value'];
          }
        }
      }

      // Add the properly formatted items to the batch.
      $items_to_index[] = $item_to_index;
    }
    try {

      // Once a batch is ready, send them over to Algolia.
      $items_indexed = $this
        ->getAlgoliaIndex()
        ->saveObjects($items_to_index);
    } catch (Exception $e) {
      throw new SearchApiException($e
        ->getMessage());
    }

    // Returns an array of properly indexed objectIDs for Search API's
    // statistics. Depending on the type of entity being indexed, this can be
    // an array of 'nids', 'uids', 'tids', etc...
    return $items_indexed['objectIDs'];
  }

  /**
   * Implements deleteItems.
   */
  public function deleteItems($ids = 'all', SearchApiIndex $index = NULL) {

    // Connect to the Algolia service.
    $this
      ->connect($index);
    if ($ids == 'all') {

      // Action triggered from the index admin page, when "Clear all indexed
      // data" button is clicked.
      $this
        ->getAlgoliaIndex()
        ->clearIndex();
    }
    else {

      // Action triggered when individual nodes are deleted. When deleting
      // multiple nodes from the admin content page, DeleteItems is being called
      // as many times as the number of nodes being deleted, making the foreach
      // irrelevant. There might be other contexts in which calls to deleteItems
      // are bundled though.
      foreach ($ids as $id) {
        $this
          ->getAlgoliaIndex()
          ->deleteObject($id);
      }
    }
  }

  /**
   * Implements search.
   */
  public function search(SearchApiQueryInterface $query) {

    // Set 'result count' at 0 by default.
    $result = array(
      'result count' => 0,
    );
    return $result;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SearchApiAbstractService::$options protected property Direct reference to the server's $options property.
SearchApiAbstractService::$server protected property
SearchApiAbstractService::addIndex public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::addIndex 1
SearchApiAbstractService::configurationFormSubmit public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::configurationFormSubmit
SearchApiAbstractService::configurationFormValidate public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::configurationFormValidate
SearchApiAbstractService::fieldsUpdated public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::fieldsUpdated 1
SearchApiAbstractService::getExtraInformation public function Returns additional, service-specific information about this server.
SearchApiAbstractService::postCreate public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::postCreate
SearchApiAbstractService::postUpdate public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::postUpdate
SearchApiAbstractService::preDelete public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::preDelete 1
SearchApiAbstractService::query public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::query
SearchApiAbstractService::removeIndex public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::removeIndex 1
SearchApiAbstractService::supportsFeature public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::supportsFeature 1
SearchApiAbstractService::__construct public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::__construct
SearchApiAlgoliaService::$algoliaIndex protected property
SearchApiAlgoliaService::configurationForm public function Defines the configuration form displayed when creating a new server. Overrides SearchApiAbstractService::configurationForm
SearchApiAlgoliaService::connect protected function Connect to the Algolia service.
SearchApiAlgoliaService::deleteItems public function Implements deleteItems. Overrides SearchApiServiceInterface::deleteItems
SearchApiAlgoliaService::getAlgoliaIndex protected function Get the Algolia index.
SearchApiAlgoliaService::getApiKey protected function Get the API key (provided by Algolia).
SearchApiAlgoliaService::getApplicationId protected function Get the ApplicationID (provided by Algolia).
SearchApiAlgoliaService::indexItems public function Implements indexItems. Overrides SearchApiServiceInterface::indexItems
SearchApiAlgoliaService::search public function Implements search. Overrides SearchApiServiceInterface::search
SearchApiAlgoliaService::setAlgoliaIndex protected function Set the Algolia index.
SearchApiAlgoliaService::viewSettings public function Implements viewSettings. Overrides SearchApiAbstractService::viewSettings