123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- <?php
- /**
- * @file
- * The Tripal Web Service Module
- */
- /**
- * @defgroup tripal_ws Tripal Web Services Module
- * @ingroup tripal
- * @{
- * The Tripal Web Services module provides functionality for managing RESTful
- * web services based on the W3C Hydra standard.
- * @}
- */
- /**
- * @defgroup tripal_api Tripal API
- * @ingroup tripal
- * @{
- * Tripal provides an application programming interface (API) to support
- * customizations and creation of new extensions.
- * @
- */
- require_once "api/tripal_ws.api.inc";
- require_once "includes/tripal_ws.field_storage.inc";
- require_once "includes/tripal_ws.fields.inc";
- require_once "includes/TripalWebService.inc";
- require_once "includes/TripalWebServiceResource.inc";
- require_once "includes/TripalWebServiceCollection.inc";
- // Web Services Fields
- require_once "includes/TripalFields/WebServicesField.inc";
- require_once "includes/TripalFields/WebServicesFieldWidget.inc";
- require_once "includes/TripalFields/WebServicesFieldFormatter.inc";
- /**
- * Implements hook_init()
- */
- function tripal_ws_init() {
- global $base_url;
- $api_url = $base_url . '/web-sevices/';
- $vocab = tripal_get_vocabulary_details('hydra');
- // Following the WC3 Hydra documentation, we want to add LINK to the header
- // of the site that indicates where the API documentation can be found.
- // This allows a hydra-enabled client to discover the API and use it.
- $attributes = array(
- 'rel' => $vocab['sw_url'] . 'apiDocumentation',
- 'href' => $api_url . '/doc/v0.1',
- );
- drupal_add_html_head_link($attributes, $header = FALSE);
- }
- /**
- * Implements hook_menu().
- * Defines all menu items needed by Tripal Core
- *
- * @ingroup tripal_ws
- */
- function tripal_ws_menu() {
- // Web Services API callbacks.
- $items['web-services'] = array(
- 'title' => 'Tripal Web Services API',
- 'page callback' => 'tripal_ws_get_services',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['remote/%/%/%/%'] = array(
- 'page callback' => 'tripal_ws_load_remote_entity',
- 'page arguments' => array(1, 2, 3, 4),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- // Tripal Web Services setting groups
- $items['admin/tripal/storage/ws'] = array(
- 'title' => 'Remote Tripal Sites',
- 'description' => t("Create mashups of content using data from this site and remote Tripal sites."),
- 'weight' => 20,
- 'page callback' => 'system_admin_menu_block_page',
- 'access arguments' => array('administer tripal'),
- 'file' => 'system.admin.inc',
- 'file path' => drupal_get_path('module', 'system'),
- );
- $items['admin/tripal/storage/ws/tripal_sites'] = array(
- 'title' => 'Configuration',
- 'description' => t('Provides information about other Tripal sites.
- This allows data exchange and communication betwen Tripal
- enabled sites through the web services.'),
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('tripal_ws_tripal_sites_form'),
- 'access arguments' => array('administer tripal'),
- 'type' => MENU_NORMAL_ITEM,
- 'weight' => 0,
- 'file' => 'includes/tripal_ws.admin.inc',
- 'file path' => drupal_get_path('module', 'tripal_ws'),
- );
- $items['admin/tripal/storage/ws/tripal_sites/edit'] = array(
- 'title' => 'Add Tripal Site',
- 'description' => 'Add a Tripal site',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('tripal_ws_tripal_sites_edit_form'),
- 'access arguments' => array('administer tripal'),
- 'file' => 'includes/tripal_ws.admin.inc',
- 'file path' => drupal_get_path('module', 'tripal_ws'),
- 'type' => MENU_LOCAL_ACTION,
- 'weight' => 2
- );
- $items['admin/tripal/storage/ws/tripal_sites/remove/%'] = array(
- 'title' => 'Remove Tripal Site',
- 'description' => 'Remove a Tripal site',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('tripal_ws_tripal_sites_remove_form', 6),
- 'access arguments' => array('administer tripal'),
- 'file' => 'includes/tripal_ws.admin.inc',
- 'file path' => drupal_get_path('module', 'tripal_ws'),
- 'type' => MENU_CALLBACK,
- 'weight' => 2
- );
- return $items;
- }
- /**
- * The callback function for all RESTful web services.
- *
- */
- function tripal_ws_get_services() {
- global $base_url;
- $service_path = $base_url . '/web-services';
- // This should go out as ld+json
- drupal_add_http_header('Content-Type', 'application/ld+json');
- // Add a link header for the vocabulary service so that clients
- // know where to find the docs.
- tripal_load_include_web_service_class('TripalDocService_v0_1');
- $service = new TripalDocService_v0_1($service_path);
- $vocab = tripal_get_vocabulary_details('hydra');
- drupal_add_http_header('Link', '<' . $service->getServicePath() . '>; rel="' . $vocab['sw_url'] . 'apiDocumentation"');
- drupal_add_http_header('Cache-Control', "no-cache");
- try {
- $ws_path = func_get_args();
- $args = $_GET;
- unset($args['q']);
- // The web services should never be cached.
- drupal_page_is_cacheable(FALSE);
- // The Tripal web services bath will be:
- // [base_path]/web-services/[service name]/v[major_version].[minor_version]
- $matches = array();
- $service = '';
- $major_version = '';
- $minor_version = '';
- $list_services = FALSE;
- // If there is no path then we should list all of the services available.
- if (empty($ws_path)) {
- tripal_ws_list_services();
- return;
- }
- // A service path will have the service name in $ws_path[0] and the
- // version in $ws_path[1]. If we check that the version is correctly
- // formatted then we can look for the service class and invoke it.
- else if (preg_match("/^v(\d+)\.(\d+)$/", $ws_path[1], $matches)) {
- $service_type = $ws_path[0];
- $major_version = $matches[1];
- $minor_version = $matches[2];
- $service_version = 'v' . $major_version . '.' . $minor_version;
- }
- // If the URL doesn't match then return not found.
- else {
- throw new Exception("Unsupported service URL: '" . $ws_path[1] . "'");
- }
- // Get the service that matches the service_name
- $service = NULL;
- $services = tripal_get_web_services();
- foreach ($services as $service_class) {
- tripal_load_include_web_service_class($service_class);
- if ($service_class::$type == $service_type) {
- $service = new $service_class($service_path);
- if ($service->getVersion() == $service_version) {
- break;
- }
- $service = NULL;
- }
- }
- // If a service was not provided then return an error.
- if (!$service) {
- throw new Exception('The service type, "' . $service_type . '", is not available');
- }
- // Adjust the path to remove the service type and the version.
- $adj_path = $ws_path;
- array_shift($adj_path);
- array_shift($adj_path);
- // Now call the service to handle the request.
- $service->setPath($adj_path);
- $service->setParams($args);
- $service->handleRequest();
- $response = $service->getResponse();
- print drupal_json_encode($response);
- }
- catch (Exception $e) {
- $service = new TripalWebService($service_path);
- $service->setError($e->getMessage());
- $response = $service->getResponse();
- print drupal_json_encode($response);
- }
- }
- /**
- * Generates the list of services as the "home page" for Tripal web services.
- */
- function tripal_ws_list_services() {
- global $base_url;
- $base_path = $base_url . '/web-services';
- // Create an instance of the TriaplWebService class and use it to build
- // the entry point for the web serivces.
- $service = new TripalWebService($base_path);
- // Get the list of web service classes.
- $services = tripal_get_web_services();
- // Create the parent resource which is a collection.
- $resource = new TripalWebServiceResource($base_path);
- // Add the vocabulary to the context.
- tripal_load_include_web_service_class('TripalDocService_v0_1');
- $service = new TripalDocService_v0_1($base_path);
- $resource->addContextItem('vocab', $service->getServicePath() . '#');
- $resource->addContextItem('EntryPoint', 'vocab:EntryPoint');
- $resource->setType('EntryPoint');
- // Now add the services as properties.
- foreach ($services as $service_class) {
- tripal_load_include_web_service_class($service_class);
- if ($service_class == 'TripalDocService_v0_1') {
- continue;
- }
- $service = new $service_class($base_path);
- $resource->addContextItem($service_class::$type, array(
- '@id' => 'vocab:EntryPoint/' . $service_class::$type,
- '@type' => '@id',
- ));
- $resource->addProperty($service_class::$type, $service->getServicePath());
- }
- $service->setResource($resource);
- $response = $service->getResponse();
- print drupal_json_encode($response);
- }
- /**
- * The callback function for all RESTful web services.
- *
- */
- function tripal_ws_services() {
- $ws_path = func_get_args();
- $params = $_GET;
- unset($params['q']);
- // The web services should never be cached.
- drupal_page_is_cacheable(FALSE);
- // Using the provided version number, determine which web services
- // verion to call.
- $version = array_shift($ws_path);
- if ($version and preg_match('/v\d+\.\d+/', $version)) {
- $api_url = 'ws/' . $version;
- // Add the file with the appropriate web services.
- module_load_include('inc', 'tripal_ws', 'includes/tripal_ws.rest_' . $version);
- $version = preg_replace('/\./', '_', $version);
- $function = 'tripal_ws_services_' . $version;
- $response = array();
- if (function_exists($function)) {
- $response = $function($api_url, $ws_path, $params);
- }
- }
- else {
- // TODO: What do we do if no version is provided?
- }
- drupal_add_http_header('Content-Type', 'application/ld+json');
- print drupal_json_encode($response);
- }
- /**
- *
- * @param $site_id
- * @param $api_version
- * @param $ctype
- * @param $id
- *
- * @return
- */
- function tripal_ws_load_remote_entity($site_id, $api_version, $ctype, $id) {
- // Get the content type on this site
- $bundle = tripal_load_bundle_entity(array('label' => $ctype));
- $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
- $term = reset($term);
- $vocab = $term->vocab;
- $query = db_select('tripal_sites', 'ts');
- $query->fields('ts');
- $query->condition('id', $site_id);
- $site = $query->execute()->fetchObject();
- if (!$site) {
- return 'Could not find specified site.';
- }
- // Get the content from the web services of the remote site.
- $url = $site->url . "/ws/v0.1/content/" . $ctype . "/" . $id;
- $json = file_get_contents($url);
- $response = json_decode($json, TRUE);
- // Set the title for this page to match the title provided.
- drupal_set_title($response['label']);
- // Attribute this data to the proper source.
- $source_url = l($response['label'], $response['ItemPage'], array('attributes' => array('target' => '_blank')));
- $content = '<div><strong>Source:</strong> ' . $site->name . ': ' . $source_url . '</div>';
- // Fake an entity so we can display this content using the same
- // entity type on this site.
- $entity = new TripalEntity(array(), 'TripalEntity');
- $entity->id = 807;
- $entity->type = 'TripalEntity';
- $entity->bundle = $bundle->name;
- $entity->term_id = $term->id;
- $entity->title = $response['label'];
- $entity->uid = 1;
- $entity->status = 1;
- // Get the fields and create a list of those that are attached to the bundle.
- $fields = field_info_fields();
- $my_fields = array();
- foreach ($fields as $field) {
- if (isset($field['bundles']['TripalEntity'])) {
- foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
- if ($bundle_name == $bundle->name) {
- $my_fields[] = $field;
- }
- }
- }
- }
- // Add in the value for the 'content_type' field.
- $entity->content_type = array();
- $entity->content_type['und'][0]['value'] = $bundle->label;
- // For each field we know about that should be attached to our bundle,
- // see if we can find a corresponding entry in the results returned from
- // the web service call. If so, then add the field to our fake entity.
- foreach ($my_fields as $field) {
- // Get the semantic web term for this field.
- $field_name = $field['field_name'];
- $settings = $field['settings'];
- // If the field does not have a semantic web mapping, then skip it.
- if (!isset($settings['semantic_web'])) {
- continue;
- }
- // Convert the term into it's db and accession elements and look it up
- // for more details.
- list($vocabulary, $accession) = explode(':', $settings['semantic_web']);
- $term = tripal_get_term_details($vocabulary, $accession);
- // Convert the term to lowercase and remove spaces so we can compare
- // correctly.
- $term_name = strtolower(preg_replace('/ /', '_', $term['name']));
- // TODO: check for the term in the response makes the assumption
- // that the term is the same on both sides. This may not be true. The
- // acutal vocab and accession for both terms should be compared.
- if (isset($response[$term_name])) {
- // If this field is of type '@id' then this links out to another
- // URL where that information can be retrieved. We'll have to
- // handle that separately.
- if (isset($response['@context'][$term_name]['@type']) and
- $response['@context'][$term_name]['@type'] == '@id') {
- $subquery = json_decode(file_get_contents($response[$term_name]), TRUE);
- // If the result is a collection then we want to add each value with
- // it's own delta value.
- if (array_key_exists('@type', $subquery) and $subquery['@type'] == 'Collection') {
- $i = 0;
- $f = array();
- foreach ($subquery['member'] as $member) {
- $f['und'][$i]['value'] = $member;
- $i++;
- }
- $entity->$field_name = $f;
- }
- // If the result is not a collection then just add it.
- else {
- unset($subquery['@context']);
- unset($subquery['@id']);
- $f = array();
- $f['und'][0]['value'] = $subquery;
- $entity->$field_name = $f;
- }
- }
- // For all fields that are currently attached, add the field and
- // value to the entity.
- else {
- $f = array();
- $f['und'][0]['value'] = $response[$term_name];
- $entity->$field_name = $f;
- }
- }
- }
- // Generate the View for this entity
- $entities = array();
- $entities[] = $entity;
- $view = entity_view('TripalEntity', $entities);
- $content .= drupal_render($view['TripalEntity'][807]);
- return $content;
- }
- function tripal_ws_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
- if ($form['#instance']['entity_type'] == 'TripalEntity') {
- $form['field']['cardinality']['#access'] = FALSE;
- }
- }
- /*
- * Returns the decoded json data for a specific field.
- */
- function tripal_ws_remote_data_single_field_pull($field, $entity_url){
- $options = array();
- $full_url = $entity_url . '/' . $field;
- $data = drupal_http_request($full_url, $options);
- if(!empty($data)){
- $data = drupal_json_decode($data->data);
- }
- return $data;
- }
- /**
- * Implements hook_entity_info_alter()
- *
- * Add the web services display as a view mode.
- */
- function tripal_ws_entity_info_alter(&$entity_info) {
- // Set the controller class for nodes to an alternate implementation of the
- // DrupalEntityController interface.
- $entity_info['TripalEntity']['view modes'] += array(
- 'tripal_ws' => array(
- 'label' => t('Tripal Web Services'),
- 'custom settings' => FALSE,
- ),
- );
- }
|