rest_oai_pmh-8.x-1.0-beta1/rest_oai_pmh.module

rest_oai_pmh.module
<?php

/**
 * @file
 * Contains rest_oai_pmh.module.
 */

use Drupal\views\Views;
use Drupal\Core\Url;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Queue\SuspendQueueException;
use Drupal\Core\Utility\Error;

/**
 * Implements hook_help().
 */
function rest_oai_pmh_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the rest_oai_pmh module.
    case 'help.page.rest_oai_pmh':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Exposes schema.org dublin core mappings in an OAI-PMH endpoint') . '</p>';
      return $output;

    default:
  }
}

/**
 * Implements hook_rest_resource_alter().
 */
function rest_oai_pmh_rest_resource_alter(&$definitions) {
  // If the repository admin set a path, override the default URI.
  $path = \Drupal::config('rest_oai_pmh.settings')->get('repository_path');
  if ($path) {
    $definitions['oai_pmh']['uri_paths']['canonical'] = $path;
    $definitions['oai_pmh']['uri_paths']['https://www.drupal.org/link-relations/create'] = $path;
  }
}

/**
 * Implements hook_metatag_tags_alter().
 */
function rest_oai_pmh_metatag_tags_alter(&$definitions) {
  // Set some dublin core metatags to allow for multiple values.
  $terms = ['dcterms_creator', 'dcterms_subject'];
  foreach ($terms as $term) {
    if (!empty($definitions[$term])) {
      $definitions[$term]['multiple'] = TRUE;
    }
  }
}

/**
 * Implements hook_entity_insert().
 */
function rest_oai_pmh_entity_insert(EntityInterface $entity) {
  rest_oai_pmh_entity_alter($entity, 'insert');
}

/**
 * Implements hook_entity_update().
 */
function rest_oai_pmh_entity_update(EntityInterface $entity) {
  rest_oai_pmh_entity_alter($entity, 'update');
}

/**
 * Implements hook_entity_delete().
 */
function rest_oai_pmh_entity_delete(EntityInterface $entity) {
  rest_oai_pmh_entity_alter($entity, 'delete');
}

/**
 * Helper function. Act when an entity is added/updated/deleted.
 */
function rest_oai_pmh_entity_alter($entity, $op = '') {
  $oai_cache_plugin_manager = \Drupal::service('plugin.manager.oai_cache');

  $config = \Drupal::config('rest_oai_pmh.settings');
  $cache_technique = $config->get('cache_technique') ?: 'liberal_cache';

  $cache_plugin = $oai_cache_plugin_manager->createInstance($cache_technique);
  $cache_plugin->clearCache($entity, $op);
}

/**
 * Create QueueWorker to execute all, or a specific set of Views.
 */
function rest_oai_pmh_cache_views($view_displays = FALSE, $queue_name = 'rest_oai_pmh_views_cache_cron') {
  // Get the queue factory.
  $queue_factory = \Drupal::service('queue');
  $queue = $queue_factory->get($queue_name);

  // If no view_displays were passed
  // get a list of all view displays set for OAI-PMH.
  if (!$view_displays) {
    $config = \Drupal::config('rest_oai_pmh.settings');
    $view_displays = $config->get('view_displays') ?: [];
    // Flush the queue since we're rebuilding everything.
    $queue->deleteQueue();

    // Truncate the tables since we're caching all the views.
    $tables = [
      'rest_oai_pmh_set',
      'rest_oai_pmh_record',
      'rest_oai_pmh_member',
    ];
    foreach ($tables as $table) {
      \Drupal::database()->truncate($table)->execute();
    }
  }

  foreach ($view_displays as $view_display) {
    [$view_id, $display_id] = explode(':', $view_display);
    $view = Views::getView($view_id);
    $view->setDisplay($display_id);

    $has_sets = FALSE;

    // Go through all the contextual filters for this View display.
    foreach ($view->display_handler->getHandlers('argument') as $contextual_filter) {
      $definition = $contextual_filter->definition;
      $set_entity_type = FALSE;

      // Look at the contextual filter definition
      // and see if it looks like an entity reference field.
      $entity_type = empty($definition['entity_type']) ? FALSE : $definition['entity_type'];
      $table = $definition['table'];
      $field = $definition['field_name'];
      $column = $definition['field'];

      // If we know the entity type of the view is querying,
      // and the field is referencing another entity
      // load the referenced entity's field storage
      // to find what type of entity reference is for.
      if ($entity_type && $column === $field . '_target_id') {
        $field_storage = \Drupal::service('entity_field.manager')
          ->getFieldStorageDefinitions($entity_type);
        if (isset($field_storage[$field])) {
          $set_entity_type = $field_storage[$field]->getSetting('target_type');
        }
      }

      // If the contextual filter is of an entity reference field.
      if ($set_entity_type) {
        // See what sort of entity is exposed
        // and see what table it's stored in
        // e.g. $entity = 'node' if $definition['entity_type'] === 'node'.
        $set_entity_storage = \Drupal::entityTypeManager()->getStorage($set_entity_type);
        $set_entity_table = $set_entity_storage->getBaseTable();

        // Get the table where the data for the entity reference is stored
        // e.g. if the field name is "field_member" and entity_type is "node"
        // $field_table = 'node__field_member';.
        $field_table = $entity_type . '__' . $field;

        // Get the database column that stores the entity's key property.
        $id = $set_entity_storage->getEntityType()->getKey('id');
        // This is what we'll perform our JOIN on
        // $column is the field that the contextual reference queries on
        // so for field_member $column = 'field_member_target_id';.
        $condition = $column . ' = ' . $id;

        // Find entities that had at least one record referencing the entity
        // in the field defined on the contextual filter.
        $query = \Drupal::database()->select($set_entity_table, 'entity');
        $query->innerJoin($field_table, 'f', $condition);
        $query->addField('entity', $id);
        $query->groupBy($id);

        // Make each entity found that's referenced a set in OAI.
        $ids = $query->execute()->fetchCol();
        foreach ($ids as $id) {
          $entity = $set_entity_storage->load($id);
          if ($entity) {
            $has_sets = TRUE;
            $data = [
              'view_id' => $view_id,
              'display_id' => $display_id,
              'arguments' => [$entity->id()],
              'set_entity_type' => $set_entity_type,
              'set_id' => $set_entity_type . ':' . $entity->id(),
              'set_label' => $entity->label(),
              'view_display' => $view_display,
            ];
            // Load the View and apply the display ID.
            $view = Views::getView($view_id);
            $view->setDisplay($display_id);
            $view->get_total_rows = TRUE;
            $view->getDisplay()->setOption('entity_reference_options', ['limit' => $view->getItemsPerPage()]);
            // Get the first set of results from the View.
            $members = $view->executeDisplay($display_id, $data['arguments']);
            // After we executed the View, see how many items were returned
            // use this to page through all results.
            $data['limit'] = $view->getItemsPerPage();
            $total = $view->total_rows;
            $offset = 0;
            while ($total > 0) {
              $data['offset'] = $offset;
              // Queue the information we found to be processed by the queue.
              $queue->createItem($data);
              if ($data['limit'] <= 0) {
                break;
              }
              $total -= $data['limit'];
              $offset += $data['limit'];
            }
          }
        }
      }
    }

    // If no contextual filter was found for this View
    // use all the View results as a single set for OAI-PMH
    // and make the set's name/id based off the View.
    if (!$has_sets) {
      $view_storage = \Drupal::entityTypeManager()->getStorage('view');
      $view = $view_storage->load($view_id);
      $display = $view->get('display');
      $data = [
        'view_id' => $view_id,
        'display_id' => $display_id,
        'arguments' => [],
        'set_entity_type' => 'view',
        'set_id' => $view_display,
        'set_label' => $display[$display_id]['display_title'],
        'view_display' => $view_display,
      ];

      // Load the View and apply the display ID.
      $view = Views::getView($view_id);
      $view->setDisplay($display_id);
      $view->getDisplay()->setOption('entity_reference_options', ['limit' => $view->getItemsPerPage()]);
      $view->get_total_rows = TRUE;
      // Get the first set of results from the View.
      $members = $view->executeDisplay($display_id);
      // After we executed the View, we'll know how many items were returned
      // use this to page through all results.
      $data['limit'] = $view->getItemsPerPage();
      $total = $view->total_rows;
      $offset = 0;
      while ($total > 0) {
        $data['offset'] = $offset;
        // Queue the information we found to be processed by the queue.
        $queue->createItem($data);
        if ($data['limit'] <= 0) {
          break;
        }
        $total -= $data['limit'];
        $offset += $data['limit'];
      }
    }
  }
}

/**
 * Helper function. Remove all sets/records exposed by a specific View display.
 */
function rest_oai_pmh_remove_sets_by_display_id($view_display) {
  $disabled_sets = \Drupal::database()->query('SELECT set_id FROM {rest_oai_pmh_set}
    WHERE view_display = :view_display', [':view_display' => $view_display])->fetchCol();
  foreach ($disabled_sets as $disabled_set) {
    [$entity_type, $entity_id] = explode(':', $disabled_set);
    rest_oai_pmh_remove_record($entity_type, $entity_id);
  }
}

/**
 * Helper function. Delete a set from OAI.
 *
 * @todo queue this?
 */
function rest_oai_pmh_remove_set($set_id) {
  // Find all records that belong to this set.
  $args = [':set_id' => $set_id];
  $disabled_records = \Drupal::database()->query('SELECT entity_type, entity_id
    FROM {rest_oai_pmh_member}
    WHERE set_id = :set_id', $args);

  foreach ($disabled_records as $disabled_record) {
    rest_oai_pmh_remove_record($disabled_record->entity_type, $disabled_record->entity_id, $set_id);
  }

  // finally, delete the set.
  \Drupal::database()->delete('rest_oai_pmh_set')
    ->condition('set_id', $set_id)
    ->execute();
}

/**
 * Helper function. Delete a record from OAI.
 */
function rest_oai_pmh_remove_record($entity_type, $entity_id, $remove_from_set = FALSE) {
  // Only attempt to remove a record if it exists as a set OR an OAI item.
  if (!rest_oai_pmh_is_valid_entity_type($entity_type)) {
    return;
  }

  $set_id = $entity_type . ':' . $entity_id;
  rest_oai_pmh_remove_set($set_id);

  // Remove this record's set associations.
  $query = \Drupal::database()->delete('rest_oai_pmh_member')
    ->condition('entity_type', $entity_type)
    ->condition('entity_id', $entity_id);
  if ($remove_from_set) {
    $query->condition('set_id', $remove_from_set);
  }
  $query->execute();

  // By default, remove the entity from OAI cache.
  $delete_entity_from_cache = TRUE;
  // If we're just removing the entity because it id in a set being removed.
  if ($remove_from_set) {
    // First check if sets are enabled.
    $config = \Drupal::config('rest_oai_pmh.settings');
    $support_sets = $config->get('support_sets') ?: FALSE;
    // If sets are supported.
    if ($support_sets) {
      // Do not delete this entity from the OAI record cache
      // if it belongs to any other sets.
      $delete_entity_from_cache = !(bool) \Drupal::database()->query('SELECT entity_id
        FROM {rest_oai_pmh_member}
        WHERE entity_type = :entity_type
          AND entity_id = :entity_id', [
            ':entity_type' => $entity_type,
            ':entity_id' => $entity_id,
          ])->fetchField();
    }
  }

  if ($delete_entity_from_cache) {
    \Drupal::database()->delete('rest_oai_pmh_record')
      ->condition('entity_type', $entity_type)
      ->condition('entity_id', $entity_id)
      ->execute();
  }
}

/**
 * Helper function. Rebuild {rest_oai_pmh_*} tables immediately.
 */
function rest_oai_pmh_rebuild_entries() {
  rest_oai_pmh_cache_views();

  $queue = \Drupal::service('queue')->get('rest_oai_pmh_views_cache_cron');
  while ($item = $queue->claimItem()) {
    rest_oai_pmh_process_queue($item);
  }

  return $item;
}

/**
 * Helper function. Run through the queue to populate OAI cache table.
 */
function rest_oai_pmh_process_queue($item) {
  $queue = \Drupal::service('queue')->get('rest_oai_pmh_views_cache_cron');
  $queue_worker = \Drupal::service('plugin.manager.queue_worker')->createInstance('rest_oai_pmh_views_cache_cron');
  try {
    $queue_worker->processItem($item->data);
    $queue->deleteItem($item);
  }
  catch (SuspendQueueException $e) {
    $queue->releaseItem($item);
    $logger = \Drupal::logger('rest_oai_pmh');
    Error::logException($logger, $e);
  }
  catch (\Exception $e) {
    $logger = \Drupal::logger('rest_oai_pmh');
    Error::logException($logger, $e);
  }
}

/**
 * Helper function to display status of OAI cache batch rebuild.
 */
function rest_oai_pmh_batch_finished($success, $results, $operations) {
  $messenger = \Drupal::messenger();
  if ($success) {
    $url_options = [
      'absolute' => TRUE,
      'query' => [
        'verb' => 'ListRecords',
        'metadataPrefix' => 'oai_dc',
      ],
    ];
    $t_args = [
      ':link' => Url::fromRoute('rest.oai_pmh.GET', [], $url_options)->toString(),
    ];
    $messenger->addStatus(t('Successfully rebuilt your OAI-PMH entries. You can now see your records at <a href=":link">:link</a>', $t_args));
  }
  else {
    $url_options = [
      'absolute' => TRUE,
    ];
    $t_args = [
      ':link' => Url::fromRoute('dblog.overview', [], $url_options)->toString(),
    ];
    $messenger->addError(t('Could not rebuild your OAI-PMH endpoint. Please check your <a href=":link">Recent log messages</a>', $t_args));
  }
}

/**
 * Helper function. Check if the entity type is exposed in OAI.
 */
function rest_oai_pmh_is_valid_entity_type($entity_type) {
  $d_args = [
    ':entity_type' => $entity_type,
  ];
  $exists = \Drupal::database()->query(<<<EOQ
SELECT 1
FROM {rest_oai_pmh_record} r
WHERE r.entity_type = :entity_type
UNION ALL
SELECT 1
FROM {rest_oai_pmh_set} s
WHERE s.entity_type = :entity_type
LIMIT 1
EOQ
    , $d_args)->fetchField();

  return $exists === '1';
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc