'. t('Visit the Services Handbook for help and information.', array('@handbook_url' => 'http://drupal.org/node/109782')) .'
';
break;
case 'admin/build/services':
$output = ''. t('Services are collections of methods available to remote applications. They are defined in modules, and may be accessed in a number of ways through server modules. Visit the Services Handbook for help and information.', array('@handbook_url' => 'http://drupal.org/node/109782')) .'
';
$output .= ''. t('All enabled services and methods are shown. Click on any method to view information or test.') .'
';
$output .= 'Enabled
Enabled With Debug
Disabled
';
break;
}
return $output;
}
/**
* Implementation of hook_perm().
*/
function services_perm() {
return array(
'administer services',
// File resource permissions
'get any binary files',
'get own binary files',
'save file information',
// System resource permissions
'get a system variable',
'set a system variable',
);
}
/**
* Implementation of hook_menu().
*/
function services_menu() {
$base = array(
'access arguments' => array('administer services'),
'file' => 'services.admin.inc',
);
$items['admin/build/services'] = array(
'title' => 'Services',
'description' => 'Manage how external applications communicates with Drupal.',
'page callback' => 'services_list_endpoint',
) + $base;
$items['admin/build/services/list'] = array(
'title' => 'List',
'page callback' => 'services_list_endpoint',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
) + $base;
$items['admin/build/services/add'] = array(
'title' => 'Add endpoint',
'page callback' => 'services_add_endpoint',
'type' => MENU_LOCAL_TASK,
) + $base;
$items['admin/build/services/%services_endpoint/edit'] = array(
'title' => 'Edit endpoint',
'page callback' => 'services_edit_endpoint',
'page arguments' => array(3),
'type' => MENU_LOCAL_TASK,
) + $base;
$items['admin/build/services/%services_endpoint/authentication'] = array(
'title' => 'Authentication',
'page callback' => 'services_edit_endpoint_authentication',
'page arguments' => array(3),
'type' => MENU_LOCAL_TASK,
'weight' => 5,
) + $base;
$items['admin/build/services/%services_endpoint/resources'] = array(
'title' => 'Resources',
'page callback' => 'services_edit_endpoint_resources',
'page arguments' => array(3),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
) + $base;
$items['admin/build/services/%services_endpoint/export'] = array(
'title' => 'Export endpoint',
'page callback' => 'drupal_get_form',
'page arguments' => array('services_export_endpoint', 3),
'type' => MENU_LOCAL_TASK,
'weight' => 20,
) + $base;
$items['admin/build/services/%services_endpoint/delete'] = array(
'title' => 'Delete endpoint',
'page callback' => 'drupal_get_form',
'page arguments' => array('services_delete_confirm_endpoint', 3),
'type' => MENU_CALLBACK,
) + $base;
$items['admin/build/services/%services_endpoint/disabledebug'] = array(
'page callback' => 'services_disable_debug_mode',
'page arguments' => array(3),
'type' => MENU_CALLBACK,
) + $base;
$items['admin/build/services/%services_endpoint/enabledebug'] = array(
'page callback' => 'services_enable_debug_mode',
'page arguments' => array(3),
'type' => MENU_CALLBACK,
) + $base;
$items['admin/build/services/%services_endpoint/disable'] = array(
'page callback' => 'services_disable_endpoint',
'page arguments' => array(3),
'type' => MENU_CALLBACK,
) + $base;
$items['admin/build/services/%services_endpoint/enable'] = array(
'page callback' => 'services_enable_endpoint',
'page arguments' => array(3),
'type' => MENU_CALLBACK,
) + $base;
$items['admin/build/services/ahah/security-options'] = array(
'page callback' => '_services_ahah_security_options',
'type' => MENU_CALLBACK,
) + $base;
$items['crossdomain.xml'] = array(
'access callback' => 'services_access_menu',
'page callback' => 'services_crossdomain_xml',
'type' => MENU_CALLBACK,
);
// Add menu items for the different endpoints
$endpoints = services_endpoint_load_all();
foreach ($endpoints as $endpoint) {
if ($endpoint->status) {
$items[$endpoint->path] = array(
'title' => 'Services endpoint',
'access callback' => 'services_access_menu',
'page callback' => 'services_endpoint_callback',
'page arguments' => array($endpoint->name),
'type' => MENU_CALLBACK,
);
}
}
return $items;
}
/**
* Access callback that always returns TRUE.
*
* This callback is necessary for services like login and logout that should
* always be wide open and accessible.
*
* *** USE THIS WITH GREAT CAUTION ***
*
* If you think you need it you are almost certainly wrong.
*/
function services_access_menu() {
return TRUE;
}
/**
* Implementation of hook_theme().
*/
function services_theme() {
return array(
'services_endpoint_index' => array(
'template' => 'services_endpoint_index',
'arguments' => array('endpoints' => NULL),
),
);
}
/**
* Returns information about the installed server modules on the system.
*
* @return array
* An associative array keyed after module name containing information about
* the installed server implementations.
*/
function services_get_servers() {
static $servers;
if (!$servers) {
$servers = array();
foreach (module_implements('server_info') as $module) {
$servers[$module] = call_user_func($module . '_server_info');
}
}
return $servers;
}
/**
* Menu system page callback for server endpoints.
*
* @param string $endpoint
* The endpoint name.
* @return void
*/
function services_endpoint_callback($endpoint_name) {
module_load_include('runtime.inc', 'services');
$endpoint = services_endpoint_load($endpoint_name);
$server = $endpoint->server;
if (function_exists($server . '_server')) {
// call the server
if($endpoint->debug) {
watchdog('services', 'Calling server: %server', array('%server' => $server . '_server'), WATCHDOG_DEBUG);
}
services_set_server_info_from_array(array(
'module' => $server,
'endpoint' => $endpoint_name,
'endpoint_path' => $endpoint->path,
'debug' => $endpoint->debug,
'drupal_path' => getcwd(),
));
if($endpoint->debug) {
watchdog('services', 'Server info main object: @info
', array('@info' => print_r(services_server_info_object(), TRUE)), WATCHDOG_DEBUG);
}
print call_user_func($server . '_server');
// Do not let this output
module_invoke_all('exit');
exit;
}
// return 404 if the server doesn't exist
drupal_not_found();
}
/**
* Callback for crossdomain.xml
*/
function services_crossdomain_xml() {
$output = '' . "\n";
$output .= '' . "\n";
$domains = module_invoke_all('services_crossdomain_domain_policy');
drupal_alter('services_crossdomain_domain_policy', $domains);
foreach ($domains as $domain => $info) {
$output .= ' ' . "\n";
if ($info['subdomain_wildcard']) {
$output .= ' ' . "\n";
}
}
$output .= '';
services_xml_output($output);
}
/**
* Implementation of hook_services_crossdomain_domain_policy().
*/
function services_services_crossdomain_domain_policy() {
// Allow our own domain and it's subdomains
return array(
$_SERVER['HTTP_HOST'] => array(
'subdomain_wildcard' => TRUE,
),
);
}
/**
* Helper function for services_crossdomain_xml().
* Outputs the necessary http headers and xml processing instruction then exits.
*
* @param string $xml
* The xml document to print.
* @return void
* This function never returns, it always exits.
*/
function services_xml_output($xml) {
$xml = '' . "\n" . $xml;
header('Connection: close');
header('Content-Length: ' . strlen($xml));
header('Content-Type: text/xml');
header('Date: ' . date('r'));
echo $xml;
exit;
}
/**
* Create a new endpoint with defaults appropriately set from schema.
*
* @return stdClass
* An endpoint initialized with the default values.
*/
function services_endpoint_new() {
ctools_include('export');
return ctools_export_new_object('services_endpoint');
}
/**
* Load a single endpoint.
*
* @param string $name
* The name of the endpoint.
* @return stdClass
* The endpoint configuration.
*/
function services_endpoint_load($name) {
ctools_include('export');
$result = ctools_export_load_object('services_endpoint', 'names', array($name));
if (isset($result[$name])) {
return $result[$name];
}
else {
$result = db_query("SELECT * FROM {services_endpoint} WHERE name = '%s'", $name);
$matches = array();
while ($endpoint = db_fetch_object($result)) {
return $endpoint;
}
}
return FALSE;
}
/**
* Load all endpoints.
*
* @return array
* Array of endpoint objects keyed by endpoint names.
*/
function services_endpoint_load_all() {
ctools_include('export');
if(!ctools_export_load_object('services_endpoint')) {
$result = db_query("SELECT * FROM {services_endpoint}");
$matches = array();
while ($endpoint = db_fetch_object($result)) {
$matches[] = $endpoint;
}
return $matches;
}
return ctools_export_load_object('services_endpoint');
}
/**
* Saves an endpoint in the database.
*
* @return void
*/
function services_endpoint_save($endpoint) {
$update = (isset($endpoint->eid)) ? array('eid') : array();
drupal_write_record('services_endpoint', $endpoint, $update);
menu_rebuild();
cache_clear_all('services:' . $endpoint->name . ':', 'cache', TRUE);
}
/**
* Remove an endpoint.
*
* @return void
*/
function services_endpoint_delete($endpoint) {
db_query("DELETE FROM {services_endpoint} WHERE name = '%s' AND eid = %d", $endpoint->name, $endpoint->eid);
menu_rebuild();
cache_clear_all('services:' . $endpoint->name . ':', 'cache', TRUE);
}
/**
* Export an endpoint.
*
* @return string
*/
function services_endpoint_export($endpoint, $indent = '') {
ctools_include('export');
$output = ctools_export_object('services_endpoint', $endpoint, $indent);
return $output;
}
/**
* Lists all available endpoints.
*
* @return array
*/
function services_endpoint_list() {
$return = array();
$endpoints = services_endpoint_load_all();
foreach ($endpoints as $endpoint) {
$return[$endpoint->name] = $endpoint->title;
}
return $return;
}
/**
* Gets all resource definitions.
*
* @param string $endpoint_name
* Optional. The endpoint endpoint that's being used.
* @return array
* An array containing all resources.
*/
function services_get_resources($endpoint_name = '') {
$cache_key = 'services:' . $endpoint_name . ':resources';
$resources = array();
if (($cache = cache_get($cache_key)) && isset($cache->data)) {
$resources = $cache->data;
}
else {
module_load_include('resource_build.inc', 'services');
$resources = _services_build_resources($endpoint_name);
cache_set($cache_key, $resources);
}
return $resources;
}
/**
* Implementation of hook_services_resources().
*/
function services_services_resources() {
module_load_include('resource_build.inc', 'services');
// Return resources representing legacy services
return array_merge(_services_core_resources(), _services_legacy_services_as_resources());
}
/**
* Returns all the controller names for a endpoint.
*
* @param string $endpoint
* The endpoint that should be used.
* @return array
* Either a non associative array containing all controller names. Or, if
* $key_by_resource was set to TRUE, a associative array where the resource
* name is the key and the value is a non-associative array containing the
* resource's controller names.
*/
function services_controllers_list($endpoint) {
$controllers = array();
$ops = array('actions', 'relationships', 'targeted actions');
$resources = services_get_resources($endpoint);
foreach ($resources as $resource_name => $res) {
// Get all basic operations
foreach (array('create', 'retrieve', 'update', 'delete', 'index') as $op) {
if (isset($res[$op])) {
$controllers[] = $resource_name . '.' . $op;
}
}
// Handle extended operatios
foreach ($ops as $op) {
if (isset($res[$op])) {
foreach ($res[$op] as $name => $def) {
// Append prefix if it isn't empty
$controllers[] = $resource_name . '.' . $name;
}
}
}
}
return $controllers;
}
/**
* Returns the requested controller.
*
* @param string $name
* The name of the controller in the format: {resource}.{name} or
* {resource}.{operation}. Examples: "node.retrieve", "system.getVariable".
* @param string $endpoint
* The endpoint that should be used.
*/
function services_controller_get($name, $endpoint) {
list($resource_name, $method) = explode('.', $name);
$ops = array('actions', 'relationships', 'targeted actions');
$resources = services_get_resources($endpoint);
if (isset($resources[$resource_name])) {
$res = $resources[$resource_name];
if (isset($res[$method])) {
return $res[$method];
}
else {
// Handle extended operatios
foreach ($ops as $op) {
if (isset($res[$op]) && isset($res[$op][$method])) {
return $res[$op][$method];
}
}
}
}
}