This is an implementation of a subset of the Doxygen documentation generator specification, tuned to produce output that best benefits the Drupal code base.
It is designed to assume the code it documents follows Drupal coding conventions, and supports the following Doxygen constructs:
The module was designed to produce the Drupal developer documentation available at !api_site.
Set up
Visit the !api_settings_page to configure the module. You must have the relevant Drupal code base on the same machine as the site hosting the API module. Follow the descriptions in the \'Branches to index\' section to set up the code base for indexing.
Indexing of PHP functions is also supported. If the site has internet access, then the default settings for the \'PHP Manual\' section should work fine. For local development environments that have a PHP manual installed, you can edit the paths to point to the appropriate locations.
The module indexes code branches during cron runs, so make sure the site has cron functionality set up properly.
', array('!api_site' => l('http://api.drupal.org', 'http://api.drupal.org', array('absolute' => TRUE)), '!api_settings_page' => l(t('API settings page'), 'admin/settings/api'))); case 'admin/settings/api/refresh': return t('Parse all indexed code files again, even if they have not been modified.'); } } function api_get_branches($_reset = FALSE) { static $branches; if (!isset($branches) || $_reset) { $result = db_query('SELECT branch_name, title, directories, excluded_directories FROM {api_branch} ORDER BY weight'); $branches = array(); while ($branch = db_fetch_object($result)) { $branches[$branch->branch_name] = $branch; } } return $branches; } /** * Implementation of hook_menu(). */ function api_menu() { $items = array(); $access_callback = 'user_access'; $access_arguments = array('access API reference'); $branches = api_get_branches(); $default_branch = variable_get('api_default_branch', NULL); // Part 1: No object, Default branch $items['api'] = array( 'title' => 'API reference', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page callback' => 'api_page_branch', 'page arguments' => array($default_branch), ); $items['api/functions'] = array( 'title' => 'Functions', 'page callback' => 'api_page_listing', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page arguments' => array($default_branch, 'function'), 'type' => MENU_CALLBACK, ); $items['api/constants'] = array( 'title' => 'Constants', 'page callback' => 'api_page_listing', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page arguments' => array($default_branch, 'constant'), 'type' => MENU_CALLBACK, ); $items['api/globals'] = array( 'title' => 'Globals', 'page callback' => 'api_page_listing', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page arguments' => array($default_branch, 'global'), 'type' => MENU_CALLBACK, ); $items['api/files'] = array( 'title' => 'Files', 'page callback' => 'api_page_listing', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page arguments' => array($default_branch, 'file'), 'type' => MENU_CALLBACK, ); $items['api/groups'] = array( 'title' => 'Topics', 'page callback' => 'api_page_listing', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'page arguments' => array($default_branch, 'group'), 'type' => MENU_CALLBACK, ); $items['api/search'] = array( 'title' => 'API Search', 'page callback' => 'drupal_get_form', 'page arguments' => array('api_search_form', $default_branch), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['apis'] = array( 'title' => 'API search', 'page callback' => 'api_search_redirect', 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['admin/settings/api'] = array( 'title' => 'API reference', 'description' => 'Configure branches for documentation.', 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_page_admin_form'), 'file' => 'api.admin.inc', ); $items['admin/settings/api/branches'] = array( 'title' => 'Branches', 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items['admin/settings/api/branches/list'] = array( 'title' => 'List', 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'type' => MENU_DEFAULT_LOCAL_TASK ); $items['admin/settings/api/branches/new'] = array( 'title' => 'New branch', 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_branch_edit_form'), 'file' => 'api.admin.inc', 'type' => MENU_LOCAL_TASK, ); $items['admin/settings/api/branches/%'] = array( 'title' => 'Edit @branch', 'title arguments' => array('@branch' => 4), 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_branch_edit_form', 4), 'file' => 'api.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/settings/api/branches/%/delete'] = array( 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_branch_delete_form', 4), 'file' => 'api.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/settings/api/php'] = array( 'title' => 'PHP manual', 'access callback' => 'user_access', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_php_manual_index_form'), 'file' => 'api.admin.inc', 'type' => MENU_LOCAL_TASK, ); $items['admin/settings/api/comments'] = array( 'title' => 'Comments', 'access arguments' => array('administer API reference'), 'page callback' => 'drupal_get_form', 'page arguments' => array('api_comments_settings_form'), 'file' => 'api.admin.inc', ); // Part 2: Object provided, default branch. $items['api/function/%api_object'] = array( 'title' => 'Function', 'load arguments' => array('function', $default_branch), 'page callback' => 'api_page_function', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/constant/%api_object'] = array( 'title' => 'Constant', 'load arguments' => array('constant', $default_branch), 'page callback' => 'api_page_constant', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/global/%api_object'] = array( 'title' => 'Global', 'load arguments' => array('global', $default_branch), 'page callback' => 'api_page_global', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/' . variable_get('api_default_project', 'drupal') . '/%api_filename'] = array( 'title' => 'File', 'load arguments' => array($default_branch), 'page callback' => 'api_page_file', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/group/%api_object'] = array( 'title' => 'Topic', 'load arguments' => array('group', $default_branch), 'page callback' => 'api_page_group', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/opensearch/%'] = array( 'page callback' => 'api_opensearch', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); $items['api/suggest/%/%'] = array( 'page callback' => 'api_suggest', 'page arguments' => array(2, 3), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); foreach ($branches as $branch) { $items['api/autocomplete/' . $branch->branch_name] = array( 'page callback' => 'api_autocomplete', 'page arguments' => array($branch->branch_name), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); // Part 3: No object, specific branch $items['api/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_branch', 'page arguments' => array($branch->branch_name), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/functions/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_listing', 'page arguments' => array($branch->branch_name, 'function'), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/constants/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_listing', 'page arguments' => array($branch->branch_name, 'constant'), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/globals/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_listing', 'page arguments' => array($branch->branch_name, 'global'), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/files/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_listing', 'page arguments' => array($branch->branch_name, 'file'), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/groups/'. $branch->branch_name] = array( 'title' => $branch->title, 'page callback' => 'api_page_listing', 'page arguments' => array($branch->branch_name, 'group'), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); // Part 4: Object provided, specific branch. $items['api/function/%api_object/'. $branch->branch_name] = array( 'title' => $branch->title, 'load arguments' => array('function', $branch->branch_name), 'page callback' => 'api_page_function', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/constant/%api_object/'. $branch->branch_name] = array( 'title' => $branch->title, 'load arguments' => array('constant', $branch->branch_name), 'page callback' => 'api_page_constant', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/global/%api_object/'. $branch->branch_name] = array( 'title' => $branch->title, 'load arguments' => array('global', $branch->branch_name), 'page callback' => 'api_page_global', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/' . variable_get('api_default_project', 'drupal') . '/%api_filename/'. $branch->branch_name] = array( 'title' => $branch->title, 'load arguments' => array($branch->branch_name), 'page callback' => 'api_page_file', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/' . variable_get('api_default_project', 'drupal') . '/%api_filename/'. $branch->branch_name .'/documentation'] = array( 'title' => 'View documentation', 'load arguments' => array($branch->branch_name), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['api/' . variable_get('api_default_project', 'drupal') . '/%api_filename/'. $branch->branch_name .'/source'] = array( 'title' => 'View source', 'load arguments' => array($branch->branch_name), 'page callback' => 'api_page_file_source', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_LOCAL_TASK, ); $items['api/group/%api_object/'. $branch->branch_name] = array( 'title' => $branch->title, 'load arguments' => array('group', $branch->branch_name), 'page callback' => 'api_page_group', 'page arguments' => array(2), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => ($branch->branch_name == $default_branch) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items['api/search/'. $branch->branch_name .'/%menu_tail'] = array( 'title' => $branch->title, 'page callback' => 'api_search_listing', 'page arguments' => array($branch->branch_name, 3), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_LOCAL_TASK, ); // Function dumps for IDEs and code editors. $items['api/function_dump/'. $branch->branch_name] = array( 'page callback' => 'api_page_function_dump', 'page arguments' => array($branch->branch_name), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); } // Redirect old links. $items['api/file/%menu_tail'] = array( 'page callback' => 'api_file_redirect', 'page arguments' => array(2), 'access callback' => TRUE, 'file' => 'legacy.inc', ); return $items; } function api_filename_load($file_name, $branch_name = NULL) { return api_object_load(str_replace('--', '/', $file_name), 'file', $branch_name); } /** * Load an object from its name, type and branch. */ function api_object_load($object_name, $object_type, $branch_name = NULL) { static $cache; if (is_null($branch_name)) { $branch_name = variable_get('api_default_branch', NULL); } $key = $object_name .':'. $object_type .':'. $branch_name; if (!isset($cache[$key])) { // Prepare the query $tables = array('{api_documentation} ad'); $fields = array('ad.*'); $where = "WHERE ad.object_name = '%s' AND ad.object_type = '%s' AND ad.branch_name = '%s'"; $arguments = array($object_name, $object_type, $branch_name); if ($object_type == 'function') { $tables[] = 'LEFT JOIN {api_function} af ON (af.did = ad.did)'; $fields[] = 'af.*'; } else if ($object_type == 'file') { $tables[] = 'LEFT JOIN {api_file} af ON (af.did = ad.did)'; $fields[] = 'af.*'; } // Now build it $cache[$key] = db_fetch_object(db_query('SELECT '. implode(', ', $fields) .' FROM '. implode(' ', $tables) .' '. $where, $arguments)); } return $cache[$key]; } /** * Implementation of hook_perm(). */ function api_perm() { return array('access API reference', 'administer API reference'); } function api_theme() { return array( 'api_branch_table' => array( 'arguments' => array('element' => NULL), ), 'api_expandable' => array( 'arguments' => array( 'prompt' => NULL, 'content' => NULL, 'class' => NULL, ), 'template' => 'templates/api-expandable', ), 'api_related_topics' => array( 'arguments' => array( 'topics' => array(), ), 'template' => 'templates/api-related-topics', ), 'api_functions' => array( 'arguments' => array( 'functions' => array(), ), 'template' => 'templates/api-functions', ), 'api_function_page' => array( 'arguments' => array( 'function' => NULL, 'signatures' => NULL, 'documentation' => NULL, 'parameters' => NULL, 'return' => NULL, 'related_topics' => NULL, 'call' => NULL, 'code' => NULL, ), 'template' => 'templates/api-function-page', ), 'api_constant_page' => array( 'arguments' => array( 'constant' => NULL, 'documentation' => NULL, 'code' => NULL, 'related_topics' => NULL, ), 'template' => 'templates/api-constant-page', ), 'api_global_page' => array( 'arguments' => array( 'global' => NULL, 'documentation' => NULL, 'code' => NULL, 'related_topics' => NULL, ), 'template' => 'templates/api-global-page', ), 'api_file_page' => array( 'arguments' => array( 'file' => NULL, 'documentation' => NULL, 'constants' => NULL, 'globals' => NULL, 'functions' => NULL, ), 'template' => 'templates/api-file-page' ), 'api_group_page' => array( 'arguments' => array( 'documentation' => NULL, 'constants' => NULL, 'globals' => NULL, 'functions' => NULL, ), 'template' => 'templates/api-group-page' ), 'api_branch_default_page' => array( 'arguments' => array( 'branch' => NULL, ), 'template' => 'templates/api-branch-default-page' ), ); } function api_init() { drupal_add_css(drupal_get_path('module', 'api') . '/jquery-autocomplete/jquery.autocomplete.css'); drupal_add_js(drupal_get_path('module', 'api') . '/jquery-autocomplete/jquery.autocomplete.js'); drupal_add_css(drupal_get_path('module', 'api') . '/api.css'); drupal_add_js(drupal_get_path('module', 'api') . '/api.js'); // Add OpenSearch autodiscovery links. foreach (array_keys(api_get_branches()) as $branch_name) { $title = t('Drupal API @branch', array('@branch' => $branch_name)); $url = url('api/opensearch/'. $branch_name, array('absolute' => TRUE)); drupal_set_html_head(''); } // If we happen to be on an API node page, redirect. if (($node = menu_get_object()) && $node->type == 'api') { $documentation = db_fetch_object(db_query('SELECT * FROM {api_documentation} WHERE did = %d', $node->nid)); drupal_goto("api/$documentation->object_type/$documentation->object_name/$documentation->branch_name"); } } function api_db_rewrite_sql($query, $primary_table, $primary_field) { if ($primary_field == 'nid') { return array('where' => $primary_table . ".type <> 'api'"); } } function api_block($op, $delta = NULL, $edit = array()) { switch ($op) { case 'list': return array( 'api-search' => array( 'info' => t('API search'), 'cache' => BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_USER, ), 'navigation' => array( 'info' => t('API navigation'), 'cache' => BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_ROLE, ), ); case 'view': $branches = api_get_branches(); $branch = api_get_active_branch(); switch ($delta) { case 'api-search': if (user_access('access API reference') && isset($branches[$branch])) { return array( 'subject' => t('Search @branch', array('@branch' => $branches[$branch]->title)), 'content' => drupal_get_form('api_search_form', $branches[$branch]->branch_name), ); } return; case 'navigation': if (user_access('access API reference') && isset($branches[$branch])) { // We forgo the menu system because we want to link to non-default // local tasks; as of Drupal 5.x, this seems impossible. if ($branch == variable_get('api_default_branch', NULL)) { $suffix = ''; } else { $suffix = '/'. $branch; } $links = array(); $links[] = l($branches[$branch]->title, 'api'. $suffix); $links[] = l(t('Constants'), 'api/constants'. $suffix); $links[] = l(t('Files'), 'api/files'. $suffix); $links[] = l(t('Functions'), 'api/functions'. $suffix); $links[] = l(t('Globals'), 'api/globals'. $suffix); $links[] = l(t('Topics'), 'api/groups'. $suffix); return array( 'content' => theme('item_list', $links), ); } return; } } } function api_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': return array(0 => t('API filter')); case 'description': return t('Add links to API objects, like theme() or theme.inc.'); case 'process': return api_filter_documentation($text, api_get_active_branch()); default: return $text; } } /** * Construct a link to an API object page. * * @param $object * An API object with object_type, object_name, and branch_name properties. * @param $file * TRUE links to the object’s containing file, FALSE links to the object * itself. * * @return * A URL string. */ function api_url($object, $file = FALSE) { // api_default_project is a placeholder for when we have real project // support. if ($file) { return 'api/' . variable_get('api_default_project', 'drupal') . '/' . str_replace('/', '--', $object->file_name) . '/' . $object->branch_name; } elseif ($object->object_type === 'file') { return 'api/' . variable_get('api_default_project', 'drupal') . '/' . str_replace('/', '--', $object->object_name) . '/' . $object->branch_name; } else { return 'api/' . $object->object_type . '/' . $object->object_name . '/' . $object->branch_name; } } /** * Show link for theme('api_expandable'). */ function api_show_l($text) { return l($text, $_REQUEST['q'], array('attributes' => array('class' => 'show-content'))); } /** * Hide link for theme('api_expandable'). */ function api_hide_l($text) { return l($text, $_REQUEST['q'], array('attributes' => array('class' => 'hide-content'))); } /** * Save an API branch. * * @param $branch * A branch object, with branch_name, title, and directories variables. * @param $old_branch_name * To replace a branch, provide the old branch name. */ function api_save_branch($branch, $old_branch_name = NULL) { if (empty($old_branch_name)) { drupal_write_record('api_branch', $branch); if (is_null(variable_get('api_default_branch', NULL))) { variable_set('api_default_branch', $branch->branch_name); } } else { if ($branch->branch_name !== $old_branch_name) { db_query("UPDATE {api_branch} SET branch_name = '%s' WHERE branch_name = '%s'", $branch->branch_name, $old_branch_name); db_query("UPDATE {api_documentation} SET branch_name = '%s' WHERE branch_name = '%s'", $branch->branch_name, $old_branch_name); db_query("UPDATE {api_file} f INNER JOIN {api_documentation} d ON d.did = f.did SET f.modified = 52 WHERE d.branch_name = '%s'", $branch->branch_name); if (variable_get('api_default_branch', NULL) === $old_branch_name) { variable_set('api_default_branch', $branch->branch_name); } } drupal_write_record('api_branch', $branch, 'branch_name'); } // Reweight all branches. $branches = api_get_branches(TRUE); uksort($branches, 'version_compare'); $weight = 0; foreach ($branches as $branch) { $branch->weight = $weight; $weight += 1; drupal_write_record('api_branch', $branch, 'branch_name'); } menu_rebuild(); } function api_get_active_branch() { static $branch; if (!isset($branch)) { if (arg(0) == 'api') { if (in_array(arg(1), array('function_dump', 'functions', 'constants', 'globals', 'files', 'groups', 'search'))) { $possible_branch = arg(2); } elseif (in_array(arg(1), array('function', 'constant', 'global', 'group'))) { $possible_branch = arg(3); } elseif (arg(1) == 'file') { // Starting at arg(2), we have a variable number of directories. The // possible branch name is either in the last, or, if we are on a // secondary local task, second to last argument. $current = arg(3); $i = 4; while (!is_null(arg($i))) { $last = $current; $current = arg($i); $i += 1; } if (in_array($current, array('documentation', 'source'))) { $possible_branch = $last; } else { $possible_branch = $current; } } else { // Maybe we are on one of the branch home pages. $possible_branch = arg(1); } } if (isset($possible_branch)) { $branches = api_get_branches(); if (isset($branches[$possible_branch])) { $branch = $possible_branch; } } if (!isset($branch)) { $branch = variable_get('api_default_branch', NULL); } } return $branch; } function api_search_form($form_state, $branch_name) { drupal_add_js(array('apiAutoCompletePath' => variable_get('api_autocomplete_path_' . $branch_name, url('api/autocomplete/' . $branch_name))), 'setting'); $form = array(); $form['branch_name'] = array( '#type' => 'value', '#value' => $branch_name, ); $form['search'] = array( '#title' => t('Function, file, or topic'), '#type' => 'textfield', '#default_value' => '', '#required' => TRUE, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Search'), ); return $form; } function api_search_form_submit($form, &$form_state) { $form_state['redirect'] = 'api/search/'. $form_state['values']['branch_name'] .'/'. $form_state['values']['search']; } function api_search_redirect() { $args = func_get_args(); if (count($args) === 0 && strpos($_GET['q'], 'apis/') !== 0) { // Handling 404. $tail = $_REQUEST['q']; } else { $tail = implode('/', $args); } drupal_goto('api/search/'. variable_get('api_default_branch', NULL) .'/'. $tail); } /** * Menu callback; perform a global search for documentation. */ function api_search_listing($branch_name) { $search_text = func_get_args(); array_shift($search_text); $search_text = implode('/', $search_text); drupal_set_title(t('Search for %search', array('%search' => $search_text))); $count = db_result(db_query("SELECT count(*) FROM {api_documentation} WHERE branch_name = '%s' AND title = '%s'", $branch_name, $search_text)); if ($count == 1) { // Exact match. $item = db_fetch_object(db_query("SELECT * FROM {api_documentation} WHERE branch_name = '%s' AND title = '%s'", $branch_name, $search_text)); drupal_goto(api_url($item)); } else { // Wildcard search. $result = pager_query("SELECT * FROM {api_documentation} WHERE branch_name = '%s' AND object_name LIKE '%%%s%%' ORDER BY title", 50, 0, NULL, $branch_name, $search_text); return api_render_listing($result, t('No search results found.')) . theme('pager', NULL, 50, 0); } } /** * Prepare a listing of documentation objects for a branch. * * @param $branch_name * A branch name. */ function api_autocomplete($branch_name, $page = TRUE) { $result = db_query("SELECT title, object_type FROM {api_documentation} WHERE branch_name = '%s' AND object_type <> 'mainpage' ORDER BY LENGTH(title)", $branch_name); while ($object = db_fetch_object($result)) { $objects[] = $object->title; } if ($page) { drupal_json($objects); } else { return drupal_to_js($objects); } } /** * Create an OpenSearch plugin for a branch. * * @param $branch_name * A branch name. * * @see https://developer.mozilla.org/en/Creating_OpenSearch_plugins_for_Firefox */ function api_opensearch($branch_name) { $valid = api_get_branches(); if (!isset($valid[$branch_name])) { return drupal_not_found(); } drupal_set_header('Content-Type: text/xml; charset=utf-8'); $short_name = t('Drupal API @branch', array('@branch' => $branch_name)); $description = t('Drupal @branch API documentation', array('@branch' => $branch_name)); if ($image = theme_get_setting('favicon')) { // Get rid of base_path that theme_get_setting() added. $image = substr($image, strlen(base_path())); } else { // Fall back on default favicon if the theme didn't provide one. $image = 'misc/favicon.ico'; } $image = url($image, array('absolute' => TRUE)); $search_url = url('api/search/'. $branch_name, array('absolute' => TRUE)) .'/{searchTerms}'; $suggest_url = url('api/suggest/'. $branch_name, array('absolute' => TRUE)) .'/{searchTerms}'; $search_form_url = url('api', array('absolute' => TRUE)); $self_url = url($_GET['q'], array('absolute' => TRUE)); print <<'. $empty_message .'
'; } } else { return theme('table', $headers, $rows); } } /** * Menu callback; produces a textual listing of all functions for use in IDEs. */ function api_page_function_dump($branch_name) { $result = db_query("SELECT d.title, d.summary, f.signature FROM {api_documentation} d INNER JOIN {api_function} f ON d.did = f.did WHERE d.branch_name = '%s' AND d.object_type = 'function'", $branch_name); while ($object = db_fetch_object($result)) { print($object->signature); print(' ### '. $object->summary ."\n"); } } /** * Menu callback; displays documentation for a function. */ function api_page_function($function) { drupal_set_title($function->title); drupal_set_breadcrumb(array( l(t('Home'), ''), l(t('API reference'), 'api'), l(basename($function->file_name), api_url($function, TRUE)), )); $last_signature = ''; $signatures = array(); $n = 0; $result = db_query("SELECT d.branch_name, f.signature FROM {api_documentation} d INNER JOIN {api_function} f ON f.did = d.did INNER JOIN {api_branch} b ON d.branch_name = b.branch_name WHERE d.object_type = 'function' AND d.title = '%s' ORDER BY b.weight", $function->title); while ($signature = db_fetch_object($result)) { if ($signature->signature == $last_signature) { // Collapse unchanged signatures to one line. $signature_info[$n - 1]['max branch name'] = $signature->branch_name; $signature_info[$n - 1]['active'] = $signature_info[$n - 1]['active'] || $signature->branch_name == $function->branch_name; } else { $tokens = token_get_all('signature); if ($tokens[1] == '&') { $name = '&'. $tokens[2][1]; } else { $name = $tokens[1][1]; } $signature_info[$n] = array( 'branch name' => $signature->branch_name, 'max branch name' => $signature->branch_name, 'active' => $signature->branch_name == $function->branch_name, 'arguments' => array(), 'other' => array(), ); $start = TRUE; $d = 0; $a = -1; $signature_info[$n]['other'][$a] = ''; foreach ($tokens as $token) { $d += in_array($token, array('(', '{', '[')) - in_array($token, array(')', '}', ']')); if ($d == 1 && $start && is_array($token) && $token[0] == T_VARIABLE) { // New argument $a += 1; $signature_info[$n]['arguments'][$a] = $token[1]; $signature_info[$n]['other'][$a] = ''; $start = FALSE; } elseif ($d >= 1 && is_array($token)) { $signature_info[$n]['other'][$a] .= $token[1]; } elseif ($d >= 1) { $signature_info[$n]['other'][$a] .= $token; // Start looking for a new argument if we see a comma. $start = $start || ($d == 1 && $token == ','); } } $last_signature = $signature->signature; $n += 1; } } foreach ($signature_info as $n => $info) { $new = array(); if (isset($signature_info[$n - 1])) { $new = array_diff($info['arguments'], $signature_info[$n - 1]['arguments']); } $old = array(); if (isset($signature_info[$n + 1])) { $old = array_diff($info['arguments'], $signature_info[$n + 1]['arguments']); } $branch_label = $info['branch name']; if ($info['branch name'] != $info['max branch name']) { $branch_label .= ' – '. $info['max branch name']; } $signature = $name . $info['other'][-1]; foreach ($signature_info[$n]['arguments'] as $key => $argument) { if (in_array($argument, $old)) { $signature .= '