clients.module in Web Service Clients 6
Same filename and directory in other branches
Clients module - handles keys and service connections and provides an API for clients @author Django Beatty - adub
File
clients.moduleView source
<?php
/**
* @file
* Clients module - handles keys and service connections
* and provides an API for clients
* @author Django Beatty - adub
*/
/**
*
*/
require_once 'clients.inc';
/**
* Implementation of hook_help()
*
* @param $path
* Which path of the site we're displaying help
* @param $arg
* Holds the current path as would be returned from arg() function
* @return
* Help text for the path
*/
function clients_help($path, $arg) {
$output = '';
switch ($path) {
case "admin/help#clients":
$output = '<p>' . t("Clients API .") . '</p>';
break;
}
return $output;
}
/**
* Implementation of hook_perm()
* @return
* An array of valid permissions for the clients module
*/
function clients_perm() {
return array(
'admin clients connections',
'admin clients resources',
);
}
/**
* Implementation of hook_menu()
*/
function clients_menu() {
$items = array();
$items['admin/settings/clients'] = array(
'title' => 'Clients',
'description' => 'Clients',
'page callback' => 'clients_resources',
'access callback' => 'clients_access_callback',
'type' => MENU_NORMAL_ITEM,
);
$items['admin/settings/clients/connections'] = array(
'title' => 'Connections',
'weight' => 1,
'description' => 'List connections',
'page callback' => 'clients_connections',
'access arguments' => array(
'admin clients connections',
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/settings/clients/resources'] = array(
'title' => 'Resources',
'weight' => 2,
'description' => 'List resources',
'page callback' => 'clients_resources',
'access arguments' => array(
'admin clients resources',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/settings/clients/resources/add'] = array(
'title' => 'Add resource',
'weight' => 1,
'description' => 'Add resource',
'page callback' => 'clients_resources_add',
'access arguments' => array(
'admin clients resources',
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/settings/clients/resources/%'] = array(
'title' => 'Show resource',
'description' => 'Show resource',
'page callback' => 'clients_resource_view',
'page arguments' => array(
4,
),
'access arguments' => array(
'admin clients resources',
),
'type' => MENU_CALLBACK,
);
$items['admin/settings/clients/resources/%/edit'] = array(
'title' => 'Edit resource',
'weight' => 1,
'description' => 'Edit data source',
'page callback' => 'clients_resources_edit',
'page arguments' => array(
4,
),
'access arguments' => array(
'admin clients resources',
),
'type' => MENU_CALLBACK,
);
$items['admin/settings/clients/resources/%/delete'] = array(
'title' => 'Delete resource',
'description' => 'Delete a resource',
'page callback' => 'clients_delete',
'page arguments' => array(
4,
3,
),
'access arguments' => array(
'admin clients connections',
),
'type' => MENU_CALLBACK,
);
$items['admin/settings/clients/cache'] = array(
'title' => 'Advanced',
'weight' => 3,
'description' => 'Clients cache settings',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'clients_admin_cache',
),
'access arguments' => array(
'admin clients resources',
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/settings/clients/connection/%'] = array(
'title' => 'Show connection',
'description' => 'Show connection',
'page callback' => 'clients_connection_view',
'page arguments' => array(
4,
),
'access arguments' => array(
'admin clients connections',
),
'type' => MENU_CALLBACK,
);
$items['admin/settings/clients/connections/%/delete'] = array(
'title' => 'Delete connection',
'description' => 'Delete a connection',
'page callback' => 'clients_delete',
'page arguments' => array(
4,
3,
),
'access arguments' => array(
'admin clients connections',
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* any defined perms in this module
*/
function clients_access_callback() {
return user_access('admin clients connections') || user_access('admin clients resources');
}
/**
* Set cache time in minutes
* @return
* Form array
*/
function clients_admin_cache() {
$form = array();
$form['clients_cache_time'] = array(
'#type' => 'select',
'#title' => t('Local cache time'),
'#default_value' => variable_get('clients_cache_time', '0'),
// change default in production
'#options' => array(
'0' => t('No cache'),
'cron' => t('Refresh on next cron run'),
'60' => t('1 hour'),
'720' => t('12 hours'),
'2880' => t('2 days'),
),
'#description' => t("Minimum cache lifetime (if set, content will refresh on the next cron run after this time has elapsed)"),
'#required' => TRUE,
);
return system_settings_form($form);
}
/**
*
*/
function clients_delete_form(&$form_state, $arg, $type) {
if ($type == 'connections') {
$service = clients_connection_load((int) $arg);
}
elseif ($type == 'resources') {
$service = clients_resource_load((int) $arg);
}
else {
/**
* @todo error
*/
$service = array();
}
$form = array();
$form['type'] = array(
'#type' => 'value',
'#value' => $type,
);
$form['cid'] = array(
'#type' => 'value',
'#value' => $arg,
);
$form['name'] = array(
'#type' => 'value',
'#value' => $service->name,
);
$form['check'] = array(
'#value' => t('<p>Really delete @service?</p>', array(
'@service' => $service->name,
)),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Delete'),
);
return $form;
}
/**
*
*/
function clients_delete($arg, $type) {
return drupal_get_form('clients_delete_form', $arg, $type);
}
/**
* @todo validate a connection has no associated resources
*/
function clients_delete_form_validate($form_id, $form_values) {
}
/**
* @todo: refactor?
*/
function clients_delete_form_submit($form_id, $form_values) {
$cid = (int) $form_values['values']['cid'];
if ($form_values['values']['type'] == 'connections') {
if ($result = db_query_range("DELETE FROM {clients_connections} WHERE cid = %d", $cid, 0, 1)) {
@db_query("DELETE FROM {clients_resources} WHERE cid = %d", $cid);
// error suppression is less expensive than a query to check if there are any resources
drupal_set_message(t('Connection deleted: ') . $form_values['values']['name']);
drupal_goto('admin/settings/clients/connections');
}
else {
drupal_set_message(t('Problem deleting connection: ') . $form_values['values']['name']);
}
}
elseif ($form_values['values']['type'] == 'resources') {
if ($result = db_query_range("DELETE FROM {clients_resources} WHERE rid = %d", $form_values['values']['cid'])) {
drupal_set_message(t('Resource deleted: ') . $form_values['values']['name']);
drupal_goto('admin/settings/clients/resources');
// @todo move this to form
}
else {
drupal_set_message(t('Problem deleting resource: ') . $form_values['values']['name']);
}
}
}
/**
* defines hook_clients_call
*/
function clients_call($resource) {
$connection = clients_connection_load((int) $resource->cid);
$result = module_invoke_all('clients_call', $connection, $resource);
module_invoke_all('clients_call_postprocess', $result, $connection, $resource);
return $result;
}
/**
* nano API for callback to resources
* @param $arg
* Array Takes the form array('name1'=>'value1', 'name2'=>'value2')
*/
function clients_setparams(&$resource, $arg) {
module_invoke_all('clients_setparams', $resource, $arg);
}
/**
* defines hook_clients_arguments()
* return array of rows with following fields:
* $foo->name, $foo->title, $foo->help,
*/
function clients_arguments($source) {
return module_invoke_all('clients_arguments', $source);
}
/**
* defines hook_clients_fields
*/
function clients_fields($resource = NULL) {
$fields = module_invoke_all('clients_fields', $resource);
// module_invoke_all performs an array_merge_recursive. This flattens out multiple fields with same name to use the first value
$result = array();
foreach ($fields as $field => $val) {
if (is_array($val['name'])) {
$val['name'] = $val['name'][0];
$val['description'] = $val['description'][0];
}
$result[$field] = $val;
}
return $result;
}
/**
* hook_clients_service_options, configure options
*/
function clients_service_options($connection_id, $wrapper, $wrapper_values, $resource) {
$service = clients_connection_load($connection_id);
return module_invoke_all('clients_service_options', $service, $wrapper, $wrapper_values, $resource);
}
/**
*
*/
function clients_connections() {
$connections = array();
foreach (array_keys(clients_connections_list()) as $cid) {
$connection = clients_connection_load($cid);
$connections[] = array(
'name' => l($connection->name, 'admin/settings/clients/connection/' . $cid),
'type' => $connection->type,
'endpoint' => $connection->endpoint,
'operations' => $connection->operations,
);
}
if (!count($connections)) {
$connections[] = array(
array(
'data' => t('No connections defined yet.'),
'colspan' => '4',
),
);
}
return theme_table(array(
'Name',
'Type',
'Endpoint',
'Operations',
), $connections);
}
/**
*
*/
function clients_resources_add() {
return drupal_get_form('clients_resources_form');
}
/**
*
*/
function clients_resources_edit($arg) {
return drupal_get_form('clients_resources_form', (int) $arg);
}
/**
*
*/
function clients_resources_form_submit($form, &$form_state) {
$values = array();
$values['name'] = $form_state['values']['name'];
$values['cid'] = $form_state['values']['clients-resource']['connection'];
// was backend in case this breaks
$values['configuration'] = $form_state['values']['clients-resource'];
// needs try catch?
if (isset($form['#rid'])) {
// edit
$values['rid'] = $form['#rid'];
if ($result = drupal_write_record('clients_resources', $values, 'rid')) {
drupal_set_message('Resource edited');
}
}
elseif ($result = drupal_write_record('clients_resources', $values)) {
drupal_set_message('Resource added');
}
drupal_goto('admin/settings/clients/resources');
}
/**
* @todo validate uniqueness of name
*/
function clients_resources_form(&$form_state, $rid = FALSE) {
$form = array();
$resource = FALSE;
if ($rid) {
// edit existing
$resource = clients_resource_load($rid);
$form['#rid'] = $rid;
}
// Register the form with ahah_helper so we can use it. Also updates
// $form_state['storage'] to ensure it contains the latest values that have
// been entered, even when the form item has temporarily been removed from
// the form. So if a form item *once* had a value, you *always* can retrieve
// it.
ahah_helper_register($form, $form_state);
$wrapper = 'clients-resource';
// can be anything
$wrapper_values = $form_state['storage'][$wrapper];
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Resource name'),
'#default_value' => $rid ? $resource->name : '',
'#size' => 50,
'#maxlength' => 100,
'#description' => t('Must be unique'),
'#required' => TRUE,
);
$connections = array();
foreach (clients_connections_list() as $cid => $connection) {
$connections[$cid] = $connection['name'];
}
$form[$wrapper] = array(
'#type' => 'fieldset',
'#title' => t('Resource'),
'#prefix' => '<div id="' . $wrapper . '">',
// This is our wrapper div.
'#suffix' => '</div>',
'#tree' => TRUE,
);
/**
* @todo fix cid being saved as string
*/
$connection_id = isset($wrapper_values['connection']) ? (int) $wrapper_values['connection'] : ($rid ? (int) $resource->configuration['connection'] : NULL);
$form[$wrapper]['connection'] = array(
'#type' => 'select',
'#title' => t('Connection'),
'#default_value' => isset($connection_id) ? $connection_id : key($connections),
// needs reset?
'#options' => $connections,
'#required' => TRUE,
'#ahah' => array(
'path' => ahah_helper_path(array(
$wrapper,
)),
'wrapper' => $wrapper,
'method' => 'replace',
'effect' => 'fade',
),
);
if (isset($connection_id)) {
// triggers hook_clients_service_options in backend modules to inject configuration form fragment here which can use ahah wrapper defined above
$form[$wrapper]['options'] = clients_service_options($connection_id, $wrapper, $wrapper_values, $resource);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
*
*/
function clients_resources() {
$sources = array();
foreach (clients_resources_load() as $resource_id => $resource) {
$connection = clients_connection_load((int) $resource['connection']);
$resources[] = array(
'name' => l($resource['name'], 'admin/settings/clients/resources/' . $resource_id),
'connection' => $connection->type . ': ' . $connection->name,
'operations' => l(t('Edit'), 'admin/settings/clients/resources/' . $resource_id . '/edit') . ' | ' . l(t('Delete'), 'admin/settings/clients/resources/' . $resource_id . '/delete'),
);
}
if (!count($resources)) {
$resources[] = array(
array(
'data' => t('No resources defined yet.'),
'colspan' => '3',
),
);
}
return theme_table(array(
'Name',
'Connection',
'Operations',
), $resources);
}
/**
* @todo hide password until clicked to prevent overshoulder attacks
* when keys are being checked
**/
function clients_resource_view($arg) {
drupal_set_breadcrumb(array(
l(t('Home'), NULL),
l(t('Administer'), 'admin'),
l(t('Site configuration'), 'admin/settings'),
l(t('Clients'), 'admin/settings/clients'),
l(t('Resources'), 'admin/settings/clients/resources'),
));
$resource = clients_resource_load((int) $arg);
$output[] = array(
'Name',
$resource->name,
);
$connection = clients_connection_load((int) $resource->cid);
$output[] = array(
'Connection',
$connection->name,
);
$output[] = array(
'Type',
$connection->type,
);
foreach ($resource->configuration['options'] as $label => $val) {
if (is_array($val)) {
$val = implode(', ', $val);
// needs to be recursive?
}
$output[] = array(
ucfirst($label),
$val,
);
}
$operations = l(t('Edit'), 'admin/settings/clients/resources/' . $arg . '/edit') . ' | ' . l(t('Delete'), 'admin/settings/clients/resources/' . $arg . '/delete');
$output[] = array(
'Operations',
$operations,
);
// add any service agnostic stuff here
return theme_table(array(), $output);
}
/**
*
*/
function clients_connection_view($arg) {
drupal_set_breadcrumb(array(
l(t('Home'), NULL),
l(t('Administer'), 'admin'),
l(t('Site configuration'), 'admin/settings'),
l(t('Clients'), 'admin/settings/clients'),
l(t('Connections'), 'admin/settings/clients/connections'),
));
$connection = clients_connection_load((int) $arg);
// modules alter the connection config and edit links
$output[] = array(
'Name',
$connection->name,
);
$output[] = array(
'Endpoint',
$connection->endpoint,
);
foreach ($connection->configuration as $label => $val) {
if (is_array($val)) {
$val = implode(', ', $val);
// needs to be recursive?
}
$output[] = array(
ucfirst($label),
nl2br($val),
);
}
$output[] = array(
'Operations',
$connection->operations,
);
return theme_table(array(), $output);
}
/**
* Implementation of hook_flush_caches()
*/
function clients_flush_caches() {
return array(
'cache_clients',
);
}
function clients_connection_edit($values) {
$values = module_invoke_all('clients_connection_edit', $values);
// by ref seems not working here...? - needs sorting
if ($resultbase = drupal_write_record('clients_connections', $values, 'cid')) {
// @todo add watchdog
drupal_set_message('Edited connection');
}
else {
drupal_set_message('Problem editing connection - drupal_write_record() result: ' . $resultbase);
}
drupal_goto('admin/settings/clients/connections');
}
function clients_connection_save($values) {
$values = module_invoke_all('clients_connection_save', $values);
if ($resultbase = drupal_write_record('clients_connections', $values)) {
// @todo add watchdog
drupal_set_message('Added connection');
}
else {
drupal_set_message('Problem adding connection - drupal_write_record() result: ' . $resultbase);
}
drupal_goto('admin/settings/clients/connections');
}
function clients_connection_load($connectionIdentifier) {
if (is_int($connectionIdentifier)) {
$result = db_query("SELECT * FROM {clients_connections} WHERE {clients_connections}.cid = %d", $connectionIdentifier);
}
elseif (is_string($connectionIdentifier)) {
$result = db_query("SELECT * FROM {clients_connections} WHERE {clients_connections}.name = '%s'", $connectionIdentifier);
}
else {
// @todo watchdog
drupal_set_message('error');
return;
// or FALSE?
}
$connection = db_fetch_object($result);
$connection->configuration = unserialize($connection->configuration);
// invoke hook for contrib modules to process configuration
module_invoke_all('clients_connection_load', $connection);
return $connection;
}
/**
* Loads all connections
* @return
* Array
*/
function clients_connections_list() {
$connections = array();
$result = db_query("SELECT * FROM {clients_connections} ORDER BY name");
while ($connection = db_fetch_object($result)) {
$connections[$connection->cid] = array(
'name' => $connection->name,
'type' => $connection->type,
'endpoint' => $connection->endpoint,
);
}
return $connections;
}
/**
* Loads all resources
* @return
* Array
*/
function clients_resources_load() {
$resources = array();
$result = db_query("SELECT * FROM {clients_resources} ORDER BY name");
while ($data = db_fetch_object($result)) {
$resources[$data->rid] = array(
'name' => $data->name,
'connection' => $data->cid,
);
}
return $resources;
}
/**
* Loads a resource
* @return
* Array
*/
function clients_resource_load($identifier) {
if (is_int($identifier)) {
$result = db_query("SELECT * FROM {clients_resources} WHERE {clients_resources}.rid = %d", $identifier);
}
elseif (is_string($identifier)) {
$result = db_query("SELECT * FROM {clients_resources} WHERE {clients_resources}.name = '%s'", $identifier);
}
else {
// @todo watchdog
drupal_set_message('error');
return;
// or FALSE?
}
$resource = db_fetch_object($result);
/**
* @TODO test resource has loaded successfully, return FALSE if not
*/
$resource->configuration = unserialize($resource->configuration);
return $resource;
}
Functions
Name | Description |
---|---|
clients_access_callback | any defined perms in this module |
clients_admin_cache | Set cache time in minutes |
clients_arguments | defines hook_clients_arguments() return array of rows with following fields: $foo->name, $foo->title, $foo->help, |
clients_call | defines hook_clients_call |
clients_connections | |
clients_connections_list | Loads all connections |
clients_connection_edit | |
clients_connection_load | |
clients_connection_save | |
clients_connection_view | |
clients_delete | |
clients_delete_form | |
clients_delete_form_submit | @todo: refactor? |
clients_delete_form_validate | @todo validate a connection has no associated resources |
clients_fields | defines hook_clients_fields |
clients_flush_caches | Implementation of hook_flush_caches() |
clients_help | Implementation of hook_help() |
clients_menu | Implementation of hook_menu() |
clients_perm | Implementation of hook_perm() |
clients_resources | |
clients_resources_add | |
clients_resources_edit | |
clients_resources_form | @todo validate uniqueness of name |
clients_resources_form_submit | |
clients_resources_load | Loads all resources |
clients_resource_load | Loads a resource |
clients_resource_view | @todo hide password until clicked to prevent overshoulder attacks when keys are being checked |
clients_service_options | hook_clients_service_options, configure options |
clients_setparams | nano API for callback to resources |