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:
@mainpage
@file
@defgroup
@ingroup
@addtogroup (as a synonym of @ ingroup)
@param
@return
@link
@see
@{
@}
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.
';
}
}
/**
* Renders an overview of documentation objects in a table.
*
* @param $result
* A database query result object.
* @param $empty_message
* An optional string to display instead of an empty table.
* @param $show_headings
* If you expect only one object type, you might not want the provided
* heading.
* @param $link_file
* Boolean : toggles the display of the file link column.
*
* @return
* Rendered HTML for the listing.
*/
function api_render_listing($result, $empty_message = NULL, $show_headings = TRUE, $link_file = FALSE) {
// Group query result by object type.
$list = array();
while ($object = db_fetch_object($result)) {
$list[$object->object_type][$object->did] = $object;
}
if (count($list) === 0) {
return is_null($empty_message) ? '' : '
';
}
$output .= $table;
}
return $output;
}
/**
* Page callback for path api/function_dump/[branch].
*
* Lists all functions in the branch in text format, 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 INNER JOIN {api_branch} b ON d.branch_id = b.branch_id WHERE b.branch_name = '%s' AND d.object_type = 'function'", $branch_name);
while ($object = db_fetch_object($result)) {
print($object->signature);
print(' ### '. $object->summary ."\n");
}
}
/**
* Sets the page title and breadcrumb for an object display page.
*/
function api_object_title_and_breadcrumb($branch, $object) {
drupal_set_title($object->title);
$breadcrumb = array(
l(t('Home'), ''),
l(t('API reference'), 'api/' . $branch->project),
);
if ($object->object_type !== 'file') {
$breadcrumb[] = l(basename($object->file_name), api_url($object, TRUE));
}
if (!empty($object->class_did)) {
$branches = api_get_branches();
$class = api_object_load((int) $object->class_did, $branches[$object->branch_id], array('interface', 'class'), $object->file_name);
$breadcrumb[] = l($class->object_name, api_url($class));
}
drupal_set_breadcrumb($breadcrumb);
}
/**
* Page callback that displays documentation for a function.
*/
function api_page_function($function) {
$branches = api_get_branches();
$branch = $branches[$function->branch_id];
api_object_title_and_breadcrumb($branch, $function);
$last_signature = '';
$signatures = array();
$n = 0;
$result = db_query("SELECT d.branch_id, d.file_name, d.object_type, d.object_name, f.signature, d.class_did FROM {api_documentation} d INNER JOIN {api_function} f ON f.did = d.did INNER JOIN {api_branch} b ON d.branch_id = b.branch_id WHERE d.object_type = 'function' AND d.title = '%s' AND d.class_did = %d ORDER BY b.weight", $function->title, $function->class_did);
while ($signature = db_fetch_object($result)) {
if ($signature->signature == $last_signature) {
// Collapse unchanged signatures to one line.
$signature_info[$n - 1]['max object'] = $signature;
$signature_info[$n - 1]['active'] = $signature_info[$n - 1]['active'] || $signature->branch_id == $function->branch_id;
}
else {
$tokens = token_get_all('signature);
// Remove class_did !== '0') {
$class = api_object_load((int) $signature->class_did, $branches[$signature->branch_id], array('interface', 'class'), $signature->file_name);
$name .= l($class->object_name, api_url($class)) . '::';
}
$name .= $tokens[0][1];
$signature_info[$n] = array(
'object' => $signature,
'max object' => $signature, // Keep track of the most-recent branch
'active' => $signature->branch_id === $function->branch_id,
'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 = $branches[$info['object']->branch_id]->branch_name;
if ($info['object']->branch_id !== $info['max object']->branch_id) {
$branch_label .= ' – '. $branches[$info['max object']->branch_id]->branch_name;
}
$signature = $name . $info['other'][-1];
foreach ($signature_info[$n]['arguments'] as $key => $argument) {
if (in_array($argument, $old)) {
$signature .= ''. $argument .'';
}
elseif (in_array($argument, $new)) {
$signature .= ''. $argument .'';
}
else {
$signature .= $argument;
}
$signature .= $info['other'][$key];
}
$signature .= ')';
$signatures[$branch_label] = array(
'signature' => $signature,
'url' => api_url($info['max object']),
'active' => $info['active'],
'status' => $branches[$info['max object']->branch_id]->status,
);
}
$documentation = api_link_documentation($function->documentation, $branch, $function->class_did);
$parameters = api_link_documentation($function->parameters, $branch, $function->class_did);
$return = api_link_documentation($function->return_value, $branch, $function->class_did);
$see = api_link_documentation($function->see, $branch, $function->class_did, TRUE);
$throws = api_link_documentation($function->throws, $branch, $function->class_did, TRUE);
$code = api_link_code($function->code, $branch, $function->class_did);
$related_topics = api_related_topics($function->did, $branch);
$call_count = db_result(db_query("SELECT count(*) FROM {api_reference_storage} r INNER JOIN {api_documentation} d ON r.from_did = d.did AND d.object_type = 'function' WHERE r.to_did = %d", $function->did));
$call = '';
if ($call_count > 0) {
$result = db_query("SELECT d.branch_id, d.object_name, d.title, d.summary, d.file_name, d.object_type FROM {api_reference_storage} r INNER JOIN {api_documentation} d ON r.from_did = d.did AND d.object_type = 'function' WHERE r.to_did = %d ORDER BY d.title", $function->did);
$call_functions = array();
while ($object = db_fetch_object($result)) {
$call_functions[] = array(
'function' => l($object->title, api_url($object)),
'file' => api_file_link($object),
'description' => api_link_documentation($object->summary, $branch),
);
}
$call_title = format_plural($call_count, '1 function calls @name()', '@count functions call @name()', array('@name' => $function->title));
$call = theme('api_expandable', '
'. api_show_l('▸ '. $call_title) .'
', '
'. api_hide_l('▾ '. $call_title) .'
'. theme('api_functions', $call_functions));
}
$output = theme('api_function_page', $branch, $function, $signatures, $documentation, $parameters, $return, $related_topics, $call, $code, $see, $throws);
$output .= _api_add_comments($function);
return $output;
}
/**
* Page callback that displays documentation for a constant.
*/
function api_page_constant($constant) {
$branches = api_get_branches();
$branch = $branches[$constant->branch_id];
api_object_title_and_breadcrumb($branch, $constant);
$documentation = api_link_documentation($constant->documentation, $branch, $constant->class_did);
$code = api_link_code($constant->code, $branch, $constant->class_did);
$related_topics = api_related_topics($constant->did, $branch);
$see = api_link_documentation($function->see, $branch, $constant->class_did, TRUE);
$output = theme('api_constant_page', $branch, $constant, $documentation, $code, $related_topics, $see);
$output .= _api_add_comments($constant);
return $output;
}
/**
* Page callback that displays documentation for a global.
*/
function api_page_global($global) {
$branches = api_get_branches();
$branch = $branches[$global->branch_id];
api_object_title_and_breadcrumb($branch, $global);
$documentation = api_link_documentation($global->documentation, $branch);
$related_topics = api_related_topics($global->did, $branch);
$code = api_link_code($global->code, $branch);
$see = api_link_documentation($global->see, $branch, $global->class_did, TRUE);
$output = theme('api_global_page', $branch, $global, $documentation, $code, $related_topics, $see);
$output .= _api_add_comments($global);
return $output;
}
/**
* Page callback that displays documentation for a property.
*/
function api_page_property($property) {
$branches = api_get_branches();
$branch = $branches[$property->branch_id];
api_object_title_and_breadcrumb($branch, $property);
$documentation = api_link_documentation($property->documentation, $branch, $property->class_did);
$related_topics = api_related_topics($property->did, $branch);
$code = api_link_code($property->code, $branch, $property->class_did);
$see = api_link_documentation($property->see, $branch, $property->class_did, TRUE);
$var = api_link_name($property->var, $branch, '', '', $property->class_did);
$output = theme('api_property_page', $branch, $property, $documentation, $code, $related_topics, $see, $var);
$output .= _api_add_comments($property);
return $output;
}
/**
* Page callback that displays documentation for a class.
*/
function api_page_class($class) {
$branches = api_get_branches();
$branch = $branches[$global->branch_id];
api_object_title_and_breadcrumb($branch, $class);
$documentation = api_link_documentation($class->documentation, $branch, $class->did);
$related_topics = api_related_topics($class->did, $branch);
$code = api_link_code($class->code, $branch, $class->did);
$see = api_link_documentation($class->see, $branch, $class->did, TRUE);
$implements = array();
$hierarchy = '';
if ($class->object_type === 'class') {
// Walk up the hierarchy
$root = $parent = $class;
while ($parent = db_fetch_object(db_query_range("SELECT ad.did, ad.branch_id, ad.file_name, ad.object_type, ad.object_name FROM {api_reference_storage} ars INNER JOIN {api_documentation} ad ON ad.did = ars.to_did WHERE ars.from_did = %d AND ars.object_type = 'class'", $parent->did, 0, 1))) {
$root = $parent;
}
$hierarchy = theme('item_list', array(api_class_hierarchy($root)));
}
elseif ($class->object_type === 'interface') {
$result = db_query("SELECT ad.did, ad.branch_id, ad.file_name, ad.object_type, ad.object_name FROM {api_reference_storage} ars INNER JOIN {api_documentation} ad ON ad.did = ars.from_did WHERE ars.to_did = %d AND ars.object_type = 'interface' GROUP BY ad.did ORDER BY ad.object_name", $class->did);
while ($object = db_fetch_object($result)) {
$implements[] = l($object->object_name, api_url($object));
}
$implements = theme('item_list', $implements);
}
$objects = api_render_listing(db_query("SELECT ad.branch_id, ad.title, ad.object_name, ad.summary, ad.object_type, ad.file_name, ao.overrides_did, ad.did FROM {api_members} am INNER JOIN {api_documentation} ad ON ad.did = am.did LEFT JOIN {api_overrides} ao ON ao.did = am.did WHERE am.class_did = %d ORDER BY title", $class->did));
$output = theme('api_class_page', $branch, $class, $documentation, $implements, $hierarchy, $objects, $code, $related_topics, $see);
$output .= _api_add_comments($class);
return $output;
}
/**
* Render a class hierarchy.
*
* @param $class
* Class object with at least did, branch_id, file_name, object_type, and
* object_name.
* @return
* HTML string.
*/
function api_class_hierarchy($class) {
// Find parent interfaces
$interfaces = $classes = array();
$result = db_query("SELECT ad.did, ad.branch_id, ad.file_name, ad.object_type, ad.object_name FROM {api_reference_storage} ars INNER JOIN {api_documentation} ad ON ad.did = ars.to_did WHERE ars.from_did = %d AND ars.object_type = 'interface' GROUP BY ars.to_did ORDER BY ad.object_name", $class->did);
while ($object = db_fetch_object($result)) {
$interfaces[] = l($object->object_name, api_url($object));
}
// Find child classes
$result = db_query("SELECT ad.did, ad.branch_id, ad.file_name, ad.object_type, ad.object_name FROM {api_reference_storage} ars INNER JOIN {api_documentation} ad ON ad.did = ars.from_did WHERE ars.to_did = %d AND ars.object_type = 'class' GROUP BY ars.from_did ORDER BY ad.object_name", $class->did);
while ($object = db_fetch_object($result)) {
$classes[] = api_class_hierarchy($object);
}
$output = l($class->object_name, api_url($class));
if (count($interfaces) > 0) {
$output .= ' ' . t('implements') . ' ' . implode(', ', $interfaces);
}
if (count($classes) > 0) {
$output .= theme('item_list', $classes);
}
return $output;
}
/**
* Page callback that displays documentation for a file.
*/
function api_page_file($file) {
$branches = api_get_branches();
$branch = $branches[$global->branch_id];
api_object_title_and_breadcrumb($branch, $file);
$documentation = api_link_documentation($file->documentation, $branch);
$see = api_link_documentation($file->see, $branch, NULL, TRUE);
$related_topics = api_related_topics($file->did, $branch);
$code = api_link_code($file->code, $branch);
$objects = api_render_listing(db_query("SELECT branch_id, title, object_name, summary, object_type, file_name, did FROM {api_documentation} WHERE file_name = '%s' AND branch_id = %d AND object_type IN ('constant', 'global', 'function', 'interface', 'class') AND class_did = 0 ORDER BY title", $file->object_name, $file->branch_id));
$output = theme('api_file_page', $file, $documentation, $objects, $code, $see, $related_topics);
$output .= _api_add_comments($file);
return $output;
}
/**
* Renders comments for a documentation object.
*
* @param $documentation_object
* Object to render comments for.
*
* @return
* Rendered comments to display with the object.
*/
function _api_add_comments($documentation_object) {
$output = '';
if (module_exists('comment') && user_access('access comments') && variable_get('comment_api', COMMENT_NODE_READ_WRITE) != COMMENT_NODE_DISABLED) {
$output .= comment_render(node_load($documentation_object->did));
if (user_access('post comments')) {
$output .= comment_form_box(array('nid' => $documentation_object->did), t('Post new comment'));
}
elseif (array_key_exists(DRUPAL_AUTHENTICATED_RID, user_roles(TRUE, 'post comments'))) {
// If authenticated users can post comments.
$options = array(
'query' => drupal_get_destination() . urlencode('#comment-form'),
);
if (variable_get('user_register', 1)) {
// Users can register themselves.
$output .= t('Login or register to post comments', array('@login' => url('user/login', $options), '@register' => url('user/register', $options)));
}
else {
// Only admins can add new users, no public registration.
$output .= t('Login to post comments', array('@login' => url('user/login', $options)));
}
}
}
return $output;
}
/**
* Page callback that displays documentation for a group.
*/
function api_page_group($group) {
$branches = api_get_branches();
$branch = $branches[$global->branch_id];
api_object_title_and_breadcrumb($branch, $group);
$documentation = api_link_documentation($group->documentation, $branch);
$see = api_link_documentation($group->see, $branch, NULL, TRUE);
$objects = api_render_listing(db_query("SELECT d.branch_id, d.object_name, d.title, d.summary, d.file_name, d.object_type, d.did FROM {api_reference_storage} r INNER JOIN {api_documentation} d ON r.from_did = d.did WHERE r.to_did = %d ORDER BY d.object_name", $group->did));
$output = theme('api_group_page', $branch, $group, $documentation, $objects, $see);
$output .= _api_add_comments($group);
return $output;
}
/**
* Lists the topics (groups) that contain the documentation object.
*
* @param $did
* ID of the documentation object to find topics for.
* @param $branch
* Branch object to find topics in.
*
* @return
* List of related topics, rendered as HTML.
*/
function api_related_topics($did, $branch) {
$header = array(
t('Name'),
t('Description'),
);
$topics = array();
$result = db_query("SELECT d.branch_id, d.object_name, d.file_name, d.object_type, d.title, d.summary FROM {api_reference_storage} r INNER JOIN {api_documentation} d ON r.to_did = d.did AND d.object_type = 'group' WHERE r.from_did = %d", $did);
while ($group = db_fetch_object($result)) {
$topics[l($group->title, api_url($group))] = api_link_documentation($group->summary, $branch);
}
if (count($topics) > 0) {
return theme('api_related_topics', $topics);
}
return '';
}
/**
* Returns a link to the file a documentation object is in.
*
* @param $object
* Documentation object.
*
* @return
* Formatted link to the file the object is in.
*/
function api_file_link($object) {
return str_replace('/', '/', dirname($object->file_name)) . '/' . l(basename($object->file_name), api_url($object, TRUE));
}
/**
* Implementation of hook_cron().
*/
function api_cron() {
include_once './'. drupal_get_path('module', 'api') .'/parser.inc';
api_update_all_branches();
}
/**
* Turns function names into links in code.
*
* @param $code
* PHP code to scan for function names.
* @param $branch
* Branch to make the links in.
*
* @return
* Code with function names formatted as links.
*/
function api_link_code($code, $branch, $class_did = NULL) {
return _api_link_documentation($code, $branch, $class_did, array('code function'));
}
/**
* Turns function names into links in documentation.
*
* @param $documentation
* Documentation to scan for function names.
* @param $branch
* Branch to make the links in.
* @param $aggressive_classes
* Try linking every word with a capital letter to a class or interface.
*
* @return
* Documentation with function names formatted as links.
*/
function api_link_documentation($documentation, $branch, $class_did = NULL, $aggressive_classes = FALSE) {
return _filter_url(api_filter_documentation($documentation, $branch, $class_did, $aggressive_classes), NULL);
}
/**
* Turns function names into links for filter.
*
* This is the process callback for the API filter supplied by api_filter().
* It turns function names into links on output, using the currently active
* branch.
*
* @param $text
* Text to filter.
* @param $branch
* Branch object to use for links.
* @param $aggressive_classes
* Try linking every word with a capital letter to a class or interface.
*
* @return
* Text with function names turned into links.
*/
function api_filter_documentation($text, $branch, $class_did = NULL, $aggressive_classes = FALSE) {
// Remove escaping from \@.
$stages = array('tags', 'link', 'function', 'file', 'constant');
if ($aggressive_classes) {
$stages[] = 'class';
}
return preg_replace('!\\\@!', '@', _api_link_documentation($text, $branch, $class_did, $stages));
}
/**
* Recursive internal callback for turning function names into links in code.
*
* @param $documentation
* PHP code to scan for function names.
* @param $branch
* Branch to make the links in.
* @stages
* Array of stages to process.
*
* @return
* Code with function names formatted as links.
*
* @see api_link_code()
*/
function _api_link_documentation($documentation, $branch, $class_did = NULL, $stages = array()) {
$patterns = array(
// Find HTML tags, which will not be filtered.
'tags' => '/(<[^>]+?'.'>)/',
// Find @link
'link' => '/' . API_RE_TAG_START . 'link\s+(.*)\s+' . API_RE_TAG_START . 'endlink/',
// Find function names, which are preceded by white space and followed by
// '('.
'function' => '!(?<=^|\s)([a-zA-Z0-9_:]+)\(!',
// Find function names in marked-up code.
'code function' => '!([a-zA-Z0-9_]+)!',
// Find file names, which are an arbitrary number of strings joined with
// '.'
'file' => '%(?<=^|\s)'. API_RE_FILENAME .'(?=$|\s|[.,:;?!])%',
// Find constants, UPPERCASE_LETTERS_WITH_UNDERSCORES.
'constant' => '/\b([A-Z_]+)\b/',
// Find class names, which have a capital letter.
'class' => '/\b(\w*[A-Z]\w*)\b/',
);
$stage = array_shift($stages);
$callback_match = 'api_link_name';
$prepend = '';
$append = '';
switch ($stage) {
case 'tags':
$callback_match = NULL;
break;
case 'link':
$callback_match = 'api_link_link';
break;
case 'function':
$append = '(';
break;
case 'code function':
$prepend = '';
$append = '';
break;
}
if (count($stages) > 0) {
$callback = '_api_link_documentation';
}
else {
$callback = NULL;
}
return api_split($patterns[$stage], $documentation, $callback_match, array($branch, $prepend, $append, $class_did), $callback, array($branch, $class_did, $stages));
}
/**
* Splits a string using a regular expression and processes the text using
* callbacks.
*
* @param $pattern
* The regular expression to match for splitting.
* @param $subject
* The string to process.
* @param $callback_match
* Function name to be called for text which matches $pattern. The first
* argument will be the parenthesized expression in the pattern. Should
* return a string. NULL to pass the text through unchanged.
* @param $callback_match_arguments
* An array of additional parameters for $callback_match.
* @param $callback
* Function name to be called for text which does not match $pattern. The
* first argument will be the text. Should return a string. NULL to pass the
* text through unchanged.
* @param $callback_arguments
* An array of additional parameters for $callback.
*
* @return
* The original string, with both matched and unmatched portions filtered by
* the appropriate callbacks.
*/
function api_split($pattern, $subject, $callback_match = NULL, $callback_match_arguments = array(), $callback = NULL, $callback_arguments = array()) {
$return = '';
$matched = FALSE;
foreach (preg_split($pattern . 'sm', $subject, -1, PREG_SPLIT_DELIM_CAPTURE) as $part) {
if ($matched) {
if (is_null($callback_match)) {
$return .= $part;
}
else {
$return .= call_user_func_array($callback_match, array_merge(array($part), $callback_match_arguments));
}
}
else {
if (is_null($callback)) {
$return .= $part;
}
else {
$return .= call_user_func_array($callback, array_merge(array($part), $callback_arguments));
}
}
$matched = !$matched;
}
return $return;
}
/**
* Links an object name to its documentation.
*
* @param $name
* Object name to link to.
* @param $branch
* Branch object indicating which branch to make the link in.
* @param $prepend
* Text to prepend on the link.
* @param $append
* Text to append on the link.
* @param $text
* Link text. If omitted, uses $name.
*
* @return
* The text as a link to the object page.
*/
function api_link_name($name, $branch, $prepend = '', $append = '', $class_did = NULL, $text = NULL, $is_link = FALSE) {
static $local_objects = array(), $php_functions;
if (!isset($local_objects[$class_did])) {
$result = db_query("SELECT ad.did, ad.branch_id, ad.object_name, ad.title, ad.object_type, ad.summary, ad.file_name, ad.class_did, (ao.did IS NULL OR ao.root_did = ao.did) is_root FROM {api_documentation} ad LEFT JOIN {api_overrides} ao ON ao.did = ad.did WHERE ad.branch_id = %d", $branch->branch_id);
$local_objects[$class_did] = array(
'group' => array(),
'item' => array(),
);
while ($object = db_fetch_object($result)) {
$link = array(
'url' => api_url($object),
'options' => array(
'attributes' => array(
'title' => $object->summary,
'class' => 'local',
),
),
);
switch ($object->object_type) {
case 'file':
$local_objects[$class_did]['item'][basename($object->object_name)] = $link;
break;
case 'group':
$local_objects[$class_did][$object->object_type][$object->object_name] = $link;
break;
default:
if ($object->class_did != 0) {
$member_name = preg_replace('/^.*::/', '', $object->title);
if ($object->class_did === $class_did) {
// The member is from the current class, it is preferred.
$local_objects[$class_did]['item'][$member_name] = $link;
$local_objects[$class_did]['item'][$member_name]['preferred'] = TRUE;
}
if ($object->is_root && (!isset($local_objects[$class_did]['item'][$member_name]) || !isset($local_objects[$class_did]['item'][$member_name]['preferred']))) {
if (isset($local_objects[$class_did]['item'][$member_name])) {
// If more than one root, link to search.
$local_objects[$class_did]['item'][$member_name] = array(
'url' => 'api/search/' . $branch->branch_name . '/' . $member_name,
'options' => array(
'attributes' => array(
'title' => t('Multiple implementations exist.'),
'class' => 'local',
),
),
);
}
else {
// Otherwise, use the top of the tree.
$local_objects[$class_did]['item'][$member_name] = $link;
}
}
}
if (isset($local_objects[$class_did]['item'][$object->object_name])) {
// Link to search results for multiple options.
$local_objects[$class_did]['item'][$object->object_name] = array(
'url' => 'api/search/' . $branch->branch_name . '/' . $object->object_name,
'options' => array(
'attributes' => array(
'title' => t('Multiple implementations exist.'),
'class' => 'local',
),
),
);
}
else {
$local_objects[$class_did]['item'][$object->object_name] = $link;
}
}
}
}
if (is_null($php_functions)) {
$result = db_query("SELECT d.object_name, d.summary FROM {api_documentation} d INNER JOIN {api_branch} b ON b.branch_id = d.branch_id AND b.type = 'php' WHERE d.object_type = 'function'");
$php_functions = array();
while ($function = db_fetch_object($result)) {
$php_functions[$function->object_name] = $function->summary;
}
}
if (is_null($text)) {
$text = $name;
}
if ($is_link && isset($local_objects[$class_did]['group'][$name])) {
return $prepend . l($text, $local_objects[$class_did]['group'][$name]['url'], $local_objects[$class_did]['group'][$name]['options']) . $append;
}
elseif (isset($local_objects[$class_did]['item'][$name])) {
return $prepend . l($text, $local_objects[$class_did]['item'][$name]['url'], $local_objects[$class_did]['item'][$name]['options']) . $append;
}
elseif (isset($php_functions[$name])) {
$link = strtr(variable_get('api_php_funcpath', 'http://php.net/!function'), array('!function' => $name));
return $prepend . l($text, $link, array('attributes' => array('title' => $php_functions[$name], 'class' => 'php-manual'))) . $append;
}
else {
return $prepend . $text . $append;
}
}
/**
* Turns text into a link, using the first word as the object name.
*
* @param $name
* Text to link.
* @param $branch
* Branch object indicating which branch to make the link in.
* @param $prepend
* Text to prepend on the link.
* @param $append
* Text to append on the link.
*
* @return
* The text as a link.
*/
function api_link_link($name, $branch, $prepend = '', $append = '', $class_did = NULL) {
$words = preg_split('/\s+/', $name);
$name = array_shift($words);
return api_link_name($name, $branch, $prepend, $append, $class_did, implode(' ', $words), TRUE);
}