Создание проекта Web-сервисов в Drupal 7

Воспользуйтесь преимуществами универсального модуля Services

Web-сервисы – это Web-приложения, обменивающиеся данными с другими Web-приложениями. Они помогают связать приложения, работающие на разных сетевых платформах, разном оборудовании, программном обеспечении и с разными базами данных, и объединить ПО и услуги из разных источников, обеспечивая гладко интегрированный сервис. Это статья о том, как создать специализированный Web-сервис, который позволяет отображать содержимое одного Drupal-сайта на другом с помощью модуля Services.

Тим Огунжоби, инженер-программист и технический писатель, Xceedia Limited

Фотография Тима ОгунжобиТим Огунжоби (Timi Ogunjobi) – технический писатель и разработчик Web-приложений. Генеральный директор компании Xceedia, специализирующейся на разработке Web- и мобильных приложений. Автор нескольких книг, три из которых посвящены Drupal. Электронный адрес: timi@xceedia.co.uk.



30.11.2012

Модуль Services позволяет создавать специализированные информационные серверы и сервисы на Drupal-сайте из единого центра настройки и администрирования главного модуля. Сервисы, включенные в модуль, позволяют вызывать информационные материалы и выводить данные из модулей Drupal File, Comment, Search, User, Menu, Node, System, Taxonomy и Views, входящих в комплект по умолчанию или добавленных пользователем. Вызывая эти сервисы, информацию можно извлекать из одного Drupal-сайта и отображать на другом, расположенном на том же локальном сервере или в другом месте. Однако модуль Services можно использовать и для интеграции приложений, не основанных на Drupal, ― с помощью внешнего Web-сервиса.

Гибкость модуля Services позволяет программно создать свой собственный сервисный модуль и интегрировать его с вызовами методов (например, Representational State Transfer [REST], JavaScript Object Notation [JSON] или XML-remote procedure call [XML-RPC]), которые входят в состав основного модуля Services. Главное преимущество модуля Services заключается в том, что он допускает интеграцию Web-сервиса с несколькими приложениями, используя стандартный код и программу модуля Drupal. Еще важнее то, что модуль Services помогает сократить время, затрачиваемое на написание собственных модулей Web-сервисов, поскольку обеспечивает стандартный интерфейс для целого ряда стандартных платформ приложений Web-сервисов.

В этой статье говорится о том, как создать модуль Web-сервисов, который будет выполнять специальный обратный вызов с Drupal-сайта с помощью модуля Service. Мы напишем специальный модуль, возвращающий набор данных из узла с информацией определенного типа. И покажем, как:

  • написать специальный модуль сервиса;
  • интегрировать этот модуль с модулем Services и проверить его (на примере простого обратного вызова, который возвращает набор узлов).

Получение и установка необходимых модулей

Прежде всего, необходимо загрузить с сайта Drupal.org следующие модули:

  • Services: Это основной модуль Services, загружаемый со страницы проекта (см. ссылку в разделе Ресурсы);
  • набор инструментов Chaos: модуль Services зависит от этого набора, поэтому его нужно установить до или во время установки модуля Services. Набор инструментов Chaos создает среду для определения конечных точек, которые можно определять и экспортировать как в базу данных, так и в код. См. ссылку на сайт загрузки в разделе Ресурсы;
  • сервер REST: для тестирования сервиса мы будем использовать сервер REST, который входит в пакет загрузки Services. Можно использовать и другие сервисы, например JSON и XML-RPC;
  • Autoload: для сервера REST требуется этот служебный модуль. Модуль Autoload позволяет другим модулям единым, универсальным способом использовать возможности класса autoloading из PHP 5. См. ссылку в разделе Ресурсы.

Установите эти модули в свою папку /sites/all/modules. Загрузив сервисы, вы найдете внутри этой папки две вложенные папки: servers и services. Папка servers содержит код модуля Web-сервисов, а основной модуль содержит поддержку сервера XML-RPC. В папке services находятся модули для предоставления Web-сервисам информации на базе Drupal, включая файлы, комментарии, узлы, меню, поиск, пользователей, системы, таксономию и представления (см. рисунок 1. Все соответствующие папки являются подмодулями модуля Services.

Рисунок 1. Содержимое папки модуля Services
Содержимое папки модуля Services

После завершения установки перейдите к списку администрирования основного модуля на своем Drupal-сайте и включите главный модуль Services, модуль Key Authentication, сервер XML-RPC и модуль Services. После включения модулей можно просматривать установленные и включенные серверы и сервисы на странице Administration наряду с основными параметрами настройки сервисов. Со страницы /admin/structure/services Web-сайта можно легко просматривать установленные модули серверов и сервисов, а также любые ключи интерфейсов прикладных программ (API), добавленные на сайт для использования с серверами и общими сервисами. На рисунке 2 приведен пример страницы Browse.

Рисунок 2. Добавление нового сервиса
Добавление нового сервиса

Нажмите кнопку Add, чтобы добавить в список свой Web-сервис и назвать его, а также добавьте разрешенный внешней домен Web-сервера, с которым вы будете поддерживать связь. Теперь Web-сервис, с которым вы установили связь, сможет обращаться к вашему сайту, работая с этими сервисами и используя данные. Вы, должно быть, уже знакомы с сайтами социальных сетей, такими как Facebook и Twitter, а также множеством других Web-приложений, которые позволяют беспрепятственно обмениваться информацией и импортировать данные пользователей для облегчения процедуры входа в систему. Страница Settings в разделе Admin > Configuration > Services отображает методы проверки подлинности и включенные параметры и предлагает применить дополнительные разрешения для доступа к информации. Во время вызова Web-сервиса разрешения полей для отдельных типов информации не будут задействованы автоматически. По умолчанию возвращаются все поля без исключения, но можно применить специальные разрешения доступа к информации на уровне полей.


Создание модуля спецсервиса

Модуль Drupal — это совокупность файлов, написанных на PHP, которые эффективно расширяют функциональность основного приложения. При более близком рассмотрении модуль ничем не отличается по структуре от любого другого файла PHP, и его можно независимо создавать, тестировать и использовать в нескольких разных установках. Код модуля обычно может обращаться ко всем переменным и структурам, а также использовать все функции ядра Drupal. Аналогично, ядро Drupal для расширения своих основных функциональных возможностей может вызывать функции, определенные в модулях, — через фиксированные интерфейсы, называемые ловушками (hooks).

Ловушки позволяют Drupal решать, например, следующие задачи:

  • добавление новых URL-адресов и страниц, определяемых модулем в рамках сайта (hook_menu);
  • добавление информации на страницы Drupal (hook_block, hook_footerи т. п.);
  • создание специальных таблиц базы данных (hook_schema).

Вы увидите определение ловушек в нескольких местах кода нового модуля, который мы создадим. Файл модуля, как и большинство других модулей Drupal, как правило, состоит из трех основных файлов: modulename.info, modulename.module и modulename.inc. Более сложный модуль может содержать еще несколько файлов.

Чтобы приступить к созданию специального сервиса или файлов модулей сервиса, добавьте в папку /sites/all/modules/services новую папку note_service для этого модуля.

Файл .info

В дополнение к папке note_service создайте новый файл note_service.info. Он будет содержать все метаданные и информацию, необходимую Drupal для включения модуля в главную страницу администрирования модулей.

В файл .info введите код, показанный в листинге 1.

Листинг 1. Файл .info сервиса заметок
name = Note Service
description = Services for the Note content type.
package = Note example
dependencies[] = services
files[] = note_service.inc
files[] = note_service.module
core = 7.x

Сохраните этот файл под именем note_service.info. Этот код определяет имя сервиса, его описание, общий пакет модулей, в который входит данный модуль, и зависимости. В данном случае это означает, что для того чтобы наш специальный модуль работал, должен быть установлен и включен модуль Services. Поместите этот файл note_service.info в свою папку модулей.

Файл .install

Файл .install указывает Drupal, как модуль должен быть установлен — в данном случае путем реализации схемы ловушек. Файл .install запускается при первом включении модуля, и его основная функция заключается в запуске процедур установки, необходимых для этого модуля. Наиболее типичная задача, решаемая файлом .install, ― это создание таблицы и полей базы данных. Инструкции по установке содержатся в функции _install(). Эта функция-ловушка вызывается при первоначальном включении модуля. Этот файл используется и для выполнения обновлений всякий раз при установке новой версии модуля. Файл .install не имеет специального синтаксиса: это просто PHP-файл с особым расширением имени файла. В листинге 2 приведен код файла .install сервиса заметок.

Листинг 2. Файл .install сервиса заметок
<?php
// note_service.install
/**
* Реализация hook_schema().
*/
function note_service_schema() {
  $schema['note'] = array(
    'description' => t('Stores information about notes.'),
    'fields' => array(
      'id' => array(
        'description' => t('The primary identifier for a note.'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'uid' => array(
        'description' => t('The user that created the note.'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'created' => array(
        'description' => t('The timestamp for when the note was created.'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'modified' => array(
        'description' => t('The timestamp for when the note was modified.'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'subject' => array(
        'description' => t('The subject of the note'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ),
      'note' => array(
        'description' => t('The note'),
        'type' => 'text',
        'size' => 'medium',
      ),
    ),
    'primary key' => array('id'),
  );
  return $schema;
}
?>

Определение сервиса

Теперь создадим файл модуля. Он содержит PHP-функцию для возврата массива данных и вывода узлов Note. Функция главным образом реализует функцию Drupal hook_services(). Детальное понимание разработки Drupal-модуля не требуется, хотя и полезно. Стоит ли говорить, что раз функции файла .module – это PHP-функции, важно, чтобы в коде файла модуля присутствовал открывающий тег <?php?

Большинство сервисов модуля Services реализуют методы CRUD (создание, извлечение, обновление, удаление, индексирование), но действия, целенаправленные действия и взаимодействие можно осуществлять и другими средствами, не описанными в этой статье. В листинге 3 приведен код для создания файла модуля.

Листинг 3. Файл .module сервиса Note
<?php
// note_service.module
/** Получение объекта заметки по идентификатору.
*
* @param int $id
* @return object
*/
function note_service_get_note($id) {
  return db_query("SELECT * FROM {note} WHERE id='".$id."'")->fetchAll();
}

/** Запись заметки в базу данных
*
* @param object $note
* @return void
*/
function note_service_write_note($note) {
  $primary_key = !empty($note->id) ? array('id') : NULL;
  drupal_write_record('note', $note, $primary_key);
}

/**
* Удаление заметки из базы данных.
*
* @param int $id
* @return void
*/
function note_service_delete_note($id) {
  db_query("DELETE FROM {note} WHERE id='".$id."'");
}

/**
* Реализация функции hook_services_services().
*/
function note_service_services_services() {
  return array(
    'note' => array(
      'retrieve' => array(
        'help' => 'Retrieves a note',
        'file' => array('file' => 'inc', 'module' => 'note_service'),
        'callback' => '_note_service_retrieve',
        'access callback' => '_note_service_access',
        'access arguments' => array('view'),
        'access arguments append' => TRUE,
        'args' => array(
          array(
            'name' => 'id',
            'type' => 'int',
            'description' => 'The id of the note to get',
            'source' => array('path' => '0'),
            'optional' => FALSE,
          ),
        ),
      ),
      'create' => array(
        'help' => 'Creates a note',
        'file' => array('file' => 'inc', 'module' => 'note_service'),
        'callback' => '_note_service_create',
        'access arguments' => array('note service create'),
        'access arguments append' => FALSE,
        'args' => array(
          array(
            'name' => 'data',
            'type' => 'struct',
            'description' => 'The note object',
            'source' => 'data',
            'optional' => FALSE,
          ),
        ),
      ),
      'update' => array(
        'help' => 'Updates a note',
        'file' => array('file' => 'inc', 'module' => 'note_service'),
        'callback' => '_note_service_update',
        'access callback' => '_note_service_access',
        'access arguments' => array('update'),
        'access arguments append' => TRUE,
        'args' => array(
          array(
            'name' => 'id',
            'type' => 'int',
            'description' => 'The id of the node to update',
            'source' => array('path' => '0'),
            'optional' => FALSE,
          ),
          array(
            'name' => 'data',
            'type' => 'struct',
            'description' => 'The note data object',
            'source' => 'data',
            'optional' => FALSE,
          ),
        ),
      ),
      'delete' => array(
        'help' => 'Deletes a note',
        'file' => array('file' => 'inc', 'module' => 'note_service'),
        'callback' => '_note_service_delete',
        'access callback' => '_note_service_access',
        'access arguments' => array('delete'),
        'access arguments append' => TRUE,
        'args' => array(
          array(
            'name' => 'nid',
            'type' => 'int',
            'description' => 'The id of the note to delete',
            'source' => array('path' => '0'),
            'optional' => FALSE,
          ),
        ),
      ),
      'index' => array(
        'help' => 'Retrieves a listing of notes',
        'file' => array('file' => 'inc', 'module' => 'note_service'),
        'callback' => '_note_service_index',
        'access callback' => 'user_access',
        'access arguments' => array('access content'),
        'access arguments append' => FALSE,
        'args' => array(
          array(
            'name' => 'page',
            'type' => 'int',
            'description' => '',
            'source' => array(
              'params' => 'page',
            ),
            'optional' => TRUE,
            'default value' => 0,
          ),
          array(
           'name' => 'parameters',
           'type' => 'array',
           'description' => '',
           'source' => 'param',
           'optional' => TRUE,
           'default value' => array(),
          ),
        ),
      ),
    ),
  );
}
?>

Создание обратных вызовов

Для создания обратных вызовов нужно создать файл note_service.inc, из которого Services сможет узнать, как найти обратные вызовы. В файл .inc будут включены следующие обратные вызовы (по отношению к методу CRUD):

  • Create callback,
  • Retrieve callback,
  • Update callback,
  • Delete callback.

Нужно также включить обратный вызов index, который получает и возвращает все заметки определенного пользователя. Укажем здесь некоторые аргументы метода, даже если они не используются. Такие аргументы нужны для указания того, что поддерживается разбиение на страницы и фильтрация листинга индекса.

Очевидно, что не все пользователи должны иметь беспрепятственный доступ для просмотра узлов Note. Поэтому нужно включить обратные вызовы доступа. На самом деле эти обратные вызовы доступа должны быть включены в главный файл модуля. Обратите внимание, что ни функции создания, ни функции редактирования не представлены, поскольку они непосредственно используют операторы user_access( ). Кроме того, в отличие от других методов, файл не регулирует права на заметку, он просто проверяет сервис Note, созданный для разрешения доступа. В листинге 4 приведен код файла .inc.

Листинг 4. Файл .inс сервиса Note
<?php
// note_service.inc
/**
* Обратный вызов для создания сервисов заметок.
*
* @param object $data
* @return object
*/
function _note_service_create($data) {
  global $user;

  unset($data->id);
  $data->uid = $user->uid;
  $data->created = time();
  $data->modified = time();

  if (!isset($data->subject)) {
    return services_error('Missing note attribute subject', 406);
  }

  if (!isset($data->note)) {
    return services_error('Missing note attribute note', 406);
  }

  note_service_write_note($data);

  return (object)array(
    'id' => $data->id,
    'uri' => services_service_uri(array('note', $data->id)),
  );
}

// note_service.inc
/**
* Обратный вызов для редактирования сервисов заметок.
*
* @param int $id
* @param object $data
* @return object
*/
function _note_service_update($id, $data) {
  global $user;
  $note = note_service_get_note($id);

  unset($data->created);
  $data->id = $id;
  $data->uid = $note->uid;
  $data->modified = time();

  note_service_write_note($data);

  return (object)array(
    'id' => $id,
    'uri' => services_service_uri(array('note', $id)),
  );
} 
/**
* Обратный вызов для извлечения сервисов заметок.
*
* @param int $id
* @return object
*/
function _note_service_retrieve($id) {
  return note_service_get_note($id);
}

/**
* Обратный вызов для удаления сервисов заметок.
*
* @param int $id
* @return object
*/
function _note_service_delete($id) {
  note_service_delete_note($id);

  return (object)array(
    'id' => $id,
  );
}

function _note_service_index($page, $parameters) {
  global $user;

  $notes = array();
  $res = db_query("SELECT * FROM {note} 
WHERE uid='".$user->uid."'ORDER BY modified DESC");
  foreach ($res as $note) {
    $notes[] = $note;
  }

  return $notes;
}

/**
* Обратный вызов для доступа к сервису заметок.
*
* @param string $op
*  Операция, подлежащая выполнению.
* @param array $args
*  Аргументы для передачи обратному вызову.
* @return bool
*  Предоставлен доступ, или нет.
*/

function _note_service_access($op, $args) {
  global $user;
  $access = FALSE;

  switch ($op) {
    case 'view':
      $note = note_service_get_note($args[0]);
      $access = user_access('note service view any note');
      $access = $access || $note->uid == $user->uid && 
      user_access('note service view own notes');
      break;
    case 'update':
      $note = note_service_get_note($args[0]->id);
      $access = user_access('note service edit any note');
      $access = $access || $note->uid == $user->uid &&  
      user_access('note service edit own notes');
      break;
    case 'delete':
      $note = note_service_get_note($args[0]);
      $access = user_access('note service delete any note');
      $access = $access || $note->uid == $user->uid && 
      user_access('note service delete own notes');
      break;
  }
  $access = TRUE;

  return $access;
}
?>

Когда в папке нового специального модуля есть файлы .info и .module, этот модуль можно включить на странице модулей Drupal Administration. Найдите модуль спецсервиса Note, установите флажок рядом с модулем, чтобы включить его, и сохраните конфигурацию модуля. Кроме того, включите модули серверов Services и REST. На этом создание специального модуля note_service завершено.


Создание конечной точки

Web-сервисы представляют собой набор программных инструментов, которые можно использоваться разными способами; три наиболее распространенных из них ― это сервис-ориентированная архитектура (SOA), RPC и REST. RPC использовался первыми инструментами Web-сервисов и поэтому стал наиболее широко распространенным и поддерживаемым стилем, несмотря на то, что он слишком тесно связан с конкретными языками или вызовами методов. REST, напротив, использует HTTP и аналогичные протоколы через знакомые операции, такие как GET, POST, PUT и DELETE, так что он больше взаимодействует с ресурсами, сохраняющими состояние, чем с операциями и сообщениями. Оба серверных инструмента включены в модуль Services (см. папку Servers). В эту папку можно загрузить и другие инструменты, но данный пример фокусируется на методе REST, потому что конечная точка универсальна.

Конечная точка указывает определенное место, в котором сервис может быть доступен с помощью определенного протокола и формата данных. Существует два способа создания конечной точки — посредством кода и посредством интерфейса администрирования. Создание конечной точки с помощью интерфейса администрирования ― это более простой вариант, так как затем можно экспортировать и вставлять код в свой модуль. Чтобы создать конечную точку, выполните следующие действия.

  1. Выберите Add из меню Admin > Structure > Services.
  2. Назовите конечную точку note.
  3. Выберите REST в качестве сервера и поместите путь к конечной точке в note.
  4. Снимите флажки Debug Mode и Session Enabled.
  5. Нажмите кнопку Save. На рисунке 3 показан процесс создания новой конечной точки сервиса.
    Рисунок 3. Новая конечная точка сервиса
    Новая конечная точка сервиса

    Увеличенная версия рисунка 3

  6. Нажмите на ссылку Services и выберите сервисы или группы сервисов, которые нужно включить. Снимите флажок notes.
  7. Нажмите кнопку Save.
  8. Щелкните на вкладке Server, затем снимите флажок application/x-www-form-urlencoded под Request parsing.
  9. Нажмите кнопку Save.

Вы создали в своем сервере REST действующую конечную точку.


Заключение

Из этой статьи вы узнали, как использовать модуль Drupal Services. Вы установили и включили дополненный модуль Services и рассмотрели функциональность его серверов и сервисов. Вы научились добавлять модули сервера для интеграции с Drupal-сайтом и его содержимым и предоставлять свой Drupal-контент внешним Web-сайтам, используя готовые подмодули Services. Вы создали специальный модуль, который можно интегрировать с модулем Services, и функциональность по умолчанию которого можно расширять, и составили вызов метода для получения обратного вызова, который выводит список всех узлов и данных для информации определенного типа.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=848031
ArticleTitle=Создание проекта Web-сервисов в Drupal 7
publish-date=11302012