Newer
Older
Karen Stevenson
committed
* Allows administrators to associate custom fields to content types.
define('CONTENT_DB_STORAGE_PER_FIELD', 0);
define('CONTENT_DB_STORAGE_PER_CONTENT_TYPE', 1);
define('CONTENT_CALLBACK_NONE', 0x0001);
define('CONTENT_CALLBACK_DEFAULT', 0x0002);
define('CONTENT_CALLBACK_CUSTOM', 0x0004);
Karen Stevenson
committed
define('CONTENT_HANDLE_CORE', 0x0001);
define('CONTENT_HANDLE_MODULE', 0x0002);
Karen Stevenson
committed
function content_help($path, $arg) {
if (preg_match('!^admin/content/types/.*/display$!', $path)) {
Yves Chedemois
committed
return t("Configure how this content type's fields and field labels should be displayed when it's viewed in teaser and full-page mode.");
}
}
/**
* Implementation of hook_devel_caches().
* Include {cache_content} in the list of tables cleared by devel's 'empty cache'
*/
function content_devel_caches() {
return array('cache_content');
}
Karen Stevenson
committed
/**
* Implementation of hook_init().
*/
function content_init() {
drupal_add_css(drupal_get_path('module', 'content') .'/content.css');
Karen Stevenson
committed
if (module_exists('views')) {
module_load_include('inc', 'content', 'content_views');
}
if (module_exists('pathauto')) {
module_load_include('inc', 'content', 'content_pathauto');
}
$items['admin/content/types/fields'] = array(
Karen Stevenson
committed
'title' => 'Fields',
'page callback' => '_content_admin_type_fields',
'access arguments' => array('administer content types'),
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
'type' => MENU_LOCAL_TASK,
);
foreach (node_get_types() as $type) {
$type_name = $type->type;
$content_type = content_types($type_name);
$type_url_str = $content_type['url_str'];
$items['admin/content/types/'. $type_url_str .'/fields'] = array(
Karen Stevenson
committed
'title' => 'Manage fields',
'page callback' => 'drupal_get_form',
'page arguments' => array('content_admin_field_overview_form', $type_name),
'access arguments' => array('administer content types'),
Karen Stevenson
committed
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
'type' => MENU_LOCAL_TASK,
'weight' => 0,
);
$items['admin/content/types/'. $type_url_str .'/display'] = array(
Karen Stevenson
committed
'title' => 'Display fields',
'page callback' => 'drupal_get_form',
'page arguments' => array('content_admin_display_overview_form', $type_name),
'access arguments' => array('administer content types'),
Karen Stevenson
committed
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
);
$items['admin/content/types/'. $type_url_str .'/add_field'] = array(
Karen Stevenson
committed
'title' => 'Add field',
'page callback' => '_content_admin_field_add',
'page arguments' => array($type_name),
'access arguments' => array('administer content types'),
Karen Stevenson
committed
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
foreach ($content_type['fields'] as $field) {
$field_name = $field['field_name'];
$items['admin/content/types/'. $type_url_str .'/fields/'. $field_name] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array('_content_admin_field', $type_name, $field_name),
Yves Chedemois
committed
'access arguments' => array('administer content types'),
Karen Stevenson
committed
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
'type' => MENU_CALLBACK,
);
Yves Chedemois
committed
$items['admin/content/types/'. $type_url_str .'/fields/'. $field_name .'/remove'] = array(
Karen Stevenson
committed
'title' => 'Remove field',
'page callback' => 'drupal_get_form',
'page arguments' => array('_content_admin_field_remove', $type_name, $field_name),
'access arguments' => array('administer content types'),
Karen Stevenson
committed
'file' => 'content_admin.inc',
'file path' => drupal_get_path('module', 'content'),
Karen Stevenson
committed
);
Karen Stevenson
committed
/**
* Implementation of hook_theme().
*/
function content_theme() {
return array(
Yves Chedemois
committed
'field' => array(
Karen Stevenson
committed
'arguments' => array('node' => NULL, 'field' => NULL, 'items' => NULL, 'teaser' => FALSE, 'page' => FALSE),
Yves Chedemois
committed
),
Karen Stevenson
committed
'content_admin_field_overview_form' => array(
Karen Stevenson
committed
'arguments' => array('form' => NULL),
Yves Chedemois
committed
),
Karen Stevenson
committed
'content_admin_display_overview_form' => array(
Karen Stevenson
committed
'arguments' => array('form' => NULL),
Yves Chedemois
committed
),
Karen Stevenson
committed
'content_admin_field_add_new_field_widget_type' => array(
Karen Stevenson
committed
'arguments' => array('form' => NULL),
Yves Chedemois
committed
),
Karen Stevenson
committed
'content_view_multiple_field' => array(
Karen Stevenson
committed
'arguments' => array('items' => NULL, 'field' => NULL, 'data' => NULL),
Yves Chedemois
committed
),
Karen Stevenson
committed
'content_multiple_values' => array(
'arguments' => array('element' => NULL),
),
Yves Chedemois
committed
);
Karen Stevenson
committed
}
Karen Stevenson
committed
* Load data for a node type's fields.
*
* When loading one of the content.module nodes, we need to let each field handle
* its own loading. This can make for a number of queries in some cases, so we
* cache the loaded object structure and invalidate it during the update process.
$cid = 'content:'. $node->nid .':'. $node->vid;
if ($cached = cache_get($cid, 'cache_content')) {
Karen Stevenson
committed
return $cached->data;
$default_additions = _content_field_invoke_default('load', $node);
if ($default_additions) {
foreach ($default_additions as $key => $value) {
$node->$key = $value;
}
}
if ($additions) {
foreach ($additions as $key => $value) {
Yves Chedemois
committed
$node->$key = $value;
$default_additions[$key] = $value;
}
}
Karen Stevenson
committed
cache_set($cid, $default_additions, 'cache_content');
return $default_additions;
Karen Stevenson
committed
* Create fields' form for a content type.
Karen Stevenson
committed
* Widget_invoke() is gone, this is the only place the widget function
* is called.
*
* Each field defines its own component of the content entry form, via its
* chosen widget.
Karen Stevenson
committed
function content_form(&$form, &$form_state) {
$node = $form['#node'];
$type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
$type = content_types($type_name);
Yves Chedemois
committed
Karen Stevenson
committed
if (count($type['fields'])) {
foreach ($type['fields'] as $field) {
$form += content_form_field($form, $form_state, $field);
}
}
Jonathan Chaffer
committed
return $form;
Karen Stevenson
committed
* Create a separate form element for each field.
*
* Extracted from content_form() to make it possible to get a subform
* for just a single field at a time.
*
* Hook_widget() picks up two new values, $count and $delta, to help
* widgets know what information to return since multiple values are
* sometimes controlled by the content module.
Karen Stevenson
committed
* @param $form
* the form to add this field element to
* @param $form_state
* the form_state for the above form
* @param $field
* the field array to use to create the form element
Jonathan Chaffer
committed
*/
Karen Stevenson
committed
function content_form_field(&$form, &$form_state, $field) {
$node = (object) $form['#node'];
Yves Chedemois
committed
$addition = array();
Karen Stevenson
committed
$widget_types = _content_widget_types();
$module = $widget_types[$field['widget']['type']]['module'];
$function = $module .'_widget';
if (function_exists($function)) {
// Prepare the values to be filled in the widget.
// We look in the following places :
// - Form submitted values
// - Node values (when editing an existing node), or pre-filled values (when
// creating a new node translation)
// - Default values set for the field (when creating a new node).
$items = array();
if (!empty($form_state['values'][$field['field_name']])) {
Yves Chedemois
committed
$items = $form_state['values'][$field['field_name']];
}
elseif (!empty($node->$field['field_name'])) {
$items = $node->$field['field_name'];
}
elseif (empty($node->nid)) {
if (content_callback('widget', 'default value', $field) != CONTENT_CALLBACK_NONE) {
Karen Stevenson
committed
$callback = content_callback('widget', 'default value', $field) == CONTENT_CALLBACK_CUSTOM ? $module .'_default_value' : 'content_default_value';
if (function_exists($callback)) {
Karen Stevenson
committed
$items = $callback($form, $form_state, $field, $items, 0);
Karen Stevenson
committed
$db_info = content_database_info($field);
Yves Chedemois
committed
$columns = array_keys($db_info['columns']);
$form_element = array();
Karen Stevenson
committed
// If content module handles multiple values for this form element,
Yves Chedemois
committed
// make this a content_multiple_values element type and iterate through
Karen Stevenson
committed
// the multiple elements to add them to the form.
Yves Chedemois
committed
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
$form_element['#type'] = 'content_multiple_values';
Karen Stevenson
committed
// @TODO
// Here's where we can intervene to control the number of items
// or add javascript to dynamically add more items,
// or take control over the delta values in some way.
Yves Chedemois
committed
$max = !empty($field['multiple']) ? count($items) + 2 : 0;
for ($delta = 0; $delta <= $max; $delta++) {
if ($element = $function($form, $form_state, $field, $items, $delta)) {
$defaults = array(
'#weight' => $delta,
'#required' => $delta == 0 && $field['required'],
// TODO : should we add some logic for title and description too ?
'#delta' => $delta,
'#columns' => $columns,
'#field' => $field,
);
$form_element[$delta] = array_merge($element, $defaults);
}
}
Karen Stevenson
committed
}
else {
Yves Chedemois
committed
// If the widget is handling multiple values (e.g optionwidgets),
// just get the field's form element and make it the zero value.
if ($element = $function($form, $form_state, $field, $items)) {
$defaults = array(
'#required' => $field['required'],
// TODO : should we add some logic for title and description too ?
'#columns' => $columns,
'#field' => $field,
);
$form_element[0] = array_merge($element, $defaults);
Karen Stevenson
committed
}
}
}
Yves Chedemois
committed
if ($form_element) {
$defaults = array(
'#tree' => TRUE,
'#weight' => $field['widget']['weight'],
'#field' => $field,
// TODO : those could probably go ?
// '#columns' => array_keys($db_info['columns']),
);
$addition[$field['field_name']] = array_merge($form_element, $defaults);
Karen Stevenson
committed
}
Yves Chedemois
committed
return $addition;
Jonathan Chaffer
committed
}
Karen Stevenson
committed
/**
* Nodeapi 'validate' op.
*
*/
function content_validate(&$node) {
_content_field_invoke('validate', $node);
_content_field_invoke_default('validate', $node);
}
/**
* Nodeapi 'presave' op.
*
*/
function content_presave(&$node) {
_content_field_invoke('presave', $node);
_content_field_invoke_default('presave', $node);
}
Jonathan Chaffer
committed
/**
Karen Stevenson
committed
* Insert node type fields.
Jonathan Chaffer
committed
*/
function content_insert(&$node) {
_content_field_invoke('insert', $node);
_content_field_invoke_default('insert', $node);
Jonathan Chaffer
committed
}
/**
Karen Stevenson
committed
* Update node type fields.
Jonathan Chaffer
committed
*/
function content_update(&$node) {
_content_field_invoke('update', $node);
_content_field_invoke_default('update', $node);
cache_clear_all('content:'. $node->nid .':'. $node->vid, 'cache_content');
Jonathan Chaffer
committed
}
/**
Karen Stevenson
committed
* Delete node type fields.
Jonathan Chaffer
committed
*/
function content_delete(&$node) {
Yves Chedemois
committed
$type = content_types($node->type);
if (!empty($type['fields'])) {
_content_field_invoke('delete', $node);
_content_field_invoke_default('delete', $node);
}
$table = _content_tablename($type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
Yves Chedemois
committed
if (db_table_exists($table)) {
db_query('DELETE FROM {'. $table .'} WHERE nid = %d', $node->nid);
Yves Chedemois
committed
}
cache_clear_all('content:'. $node->nid, 'cache_content', TRUE);
Karen Stevenson
committed
}
/**
* Nodeapi 'delete_revision' op.
*
* Delete node type fields for a revision.
Karen Stevenson
committed
*/
function content_delete_revision(&$node) {
Yves Chedemois
committed
$type = content_types($node->type);
if (!empty($type['fields'])) {
Karen Stevenson
committed
_content_field_invoke('delete revision', $node);
_content_field_invoke_default('delete revision', $node);
}
$table = _content_tablename($type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
Yves Chedemois
committed
if (db_table_exists($table)) {
db_query('DELETE FROM {'. $table .'} WHERE vid = %d', $node->vid);
Yves Chedemois
committed
}
cache_clear_all('content:'. $node->nid .':'. $node->vid, 'cache_content');
Jonathan Chaffer
committed
}
Karen Stevenson
committed
* Generate field render arrays.
*/
function content_view(&$node, $teaser = FALSE, $page = FALSE) {
Yves Chedemois
committed
$additions = _content_field_invoke_default('view', $node);
$node->content = array_merge((array) $node->content, $additions);
/**
* Nodeapi 'prepare translation' op.
*
* Generate field render arrays.
*/
function content_prepare_translation(&$node) {
$default_additions = _content_field_invoke_default('prepare translation', $node);
$node = (object) array_merge((array) $node, $default_additions);
Yves Chedemois
committed
/**
* Implementation of hook_nodeapi().
*/
function content_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
Karen Stevenson
committed
case 'load':
return content_load($node);
Karen Stevenson
committed
case 'validate':
content_validate($node);
break;
Karen Stevenson
committed
case 'presave':
content_presave($node);
break;
Karen Stevenson
committed
case 'insert':
content_insert($node);
break;
case 'update':
content_update($node);
break;
case 'delete':
content_delete($node);
break;
Karen Stevenson
committed
content_delete_revision($node);
break;
case 'view':
content_view($node, $teaser, $page);
case 'prepare translation':
content_prepare_translation($node);
break;
Karen Stevenson
committed
}
}
/**
* Implementation of hook_form_alter().
*/
function content_form_alter(&$form, $form_state, $form_id) {
Karen Stevenson
committed
if (isset($form['type'])) {
if ($form['type']['#value'] .'_node_form' == $form_id) {
Karen Stevenson
committed
$form = array_merge($form, content_form($form, $form_state));
Karen Stevenson
committed
}
}
/**
* Make sure that CCK content type info is synched with node type data
* any time the content module is enabled.
function content_enable() {
Karen Stevenson
committed
module_load_include('inc', 'content', 'content_admin');
module_load_include('inc', 'content', 'content_crud');
content_types_rebuild();
Jonathan Chaffer
committed
/**
* Implementation of hook_field(). Handles common field housekeeping.
*
* This implementation is special, as content.module does not define any field
* types. Instead, this function gets called after the type-specific hook, and
Jonathan Chaffer
committed
*/
function content_field($op, &$node, $field, &$node_field, $teaser, $page) {
Jonathan Chaffer
committed
$db_info = content_database_info($field);
switch ($op) {
case 'validate':
// TODO : here we could validate that the number of multiple data is correct ?
break;
Yves Chedemois
committed
case 'view':
if ($node->build_mode == NODE_BUILD_NORMAL) {
$context = $teaser ? 'teaser' : 'full';
}
else {
$context = $node->build_mode;
}
$formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default';
$value = '';
if ($formatter != 'hidden') {
foreach ($node_field as $delta => $item) {
$node_field[$delta]['view'] = content_format($field, $item, $formatter, $node);
}
Yves Chedemois
committed
// Do not include field labels when indexing content.
if ($context == NODE_BUILD_SEARCH_INDEX) {
$field['display_settings']['label']['format'] = 'hidden';
}
Yves Chedemois
committed
$value = theme('field', $node, $field, $node_field, $teaser, $page);
}
$addition[$field['field_name']] = array(
'#weight' => $field['widget']['weight'],
'#value' => $value,
'#access' => $formatter != 'hidden',
);
return $addition;
case 'prepare translation':
$addition = array();
if (isset($node->translation_source->$field['field_name'])) {
$addition[$field['field_name']] = $node->translation_source->$field['field_name'];
}
return $addition;
/**
* TODO : PHPdoc
*/
function content_storage($op, $node) {
$type_name = $node->type;
$type = content_types($type_name);
Jonathan Chaffer
committed
switch ($op) {
case 'load':
// OPTIMIZE : load all non multiple fields in a single JOIN query ?
// warning : 61-join limit in MySQL ?
$additions = array();
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
// For each table used by this content type,
foreach ($type['tables'] as $table) {
$schema = drupal_get_schema($table);
$query = 'SELECT * FROM {'. $table .'} WHERE vid = %d';
// If we're loading a table for a multiple field,
// we fetch all rows (values) ordered by delta,
// else we only fetch one row.
$result = isset($schema['fields']['delta']) ? db_query($query .' ORDER BY delta', $node->vid) : db_query_range($query, $node->vid, 0, 1);
// For each table row, populate the fields.
while ($row = db_fetch_array($result)) {
// For each field stored in the table, add the field item.
foreach ($schema['content fields'] as $field_name) {
$item = array();
$field = content_fields($field_name, $type_name);
$db_info = content_database_info($field);
// For each column declared by the field, populate the item.
foreach ($db_info['columns'] as $column => $attributes) {
$item[$column] = $row[$attributes['column']];
}
// Add the item to the field values for the node.
if (!isset($additions[$field_name])) {
$additions[$field_name] = array();
}
$additions[$field_name][] = $item;
}
}
Jonathan Chaffer
committed
}
return $additions;
case 'update':
foreach ($type['tables'] as $table) {
$schema = drupal_get_schema($table);
foreach ($schema['content fields'] as $field_name) {
$field = content_fields($field_name, $type_name);
// Multiple fields need specific handling, we'll deal with them later on.
if ($field['multiple']) {
continue;
$db_info = content_database_info($field);
foreach ($db_info['columns'] as $column => $attributes) {
$record[$attributes['column']] = $node->{$field_name}[0][$column];
Jonathan Chaffer
committed
}
Jonathan Chaffer
committed
}
if (count($record)) {
$record['nid'] = $node->nid;
$record['vid'] = $node->vid;
content_write_record($table, $record, $op == 'update' ? 'vid' : FALSE);
Jonathan Chaffer
committed
}
Jonathan Chaffer
committed
// Handle multiple fields.
foreach ($type['fields'] as $field) {
Jonathan Chaffer
committed
if ($field['multiple']) {
$db_info = content_database_info($field);
// Delete and insert, rather than update, in case a value was added.
if ($op == 'update') {
db_query('DELETE FROM {'. $db_info['table'] .'} WHERE vid = %d', $node->vid);
Jonathan Chaffer
committed
}
foreach ($node->$field['field_name'] as $delta => $item) {
foreach ($db_info['columns'] as $column => $attributes) {
$record['nid'] = $node->nid;
$record['vid'] = $node->vid;
$record['delta'] = $delta;
content_write_record($db_info['table'], $record);
Jonathan Chaffer
committed
}
Jonathan Chaffer
committed
}
}
Jonathan Chaffer
committed
case 'delete':
foreach ($type['tables'] as $table) {
db_query('DELETE FROM {'. $table .'} WHERE nid = %d', $node->nid);
}
break;
Jonathan Chaffer
committed
case 'delete revision':
foreach ($type['tables'] as $table) {
db_query('DELETE FROM {'. $table .'} WHERE vid = %d', $node->vid);
}
break;
Jonathan Chaffer
committed
}
}
/**
* Save a record to the database based upon the schema. Default values are
* filled in for missing items, and 'serial' (auto increment) types are
* filled in with IDs.
*
* Stolen from http://drupal.org/node/169982#comment-303480
*
* @param $table
* The name of the table; this must exist in schema API.
* @param $object
* The object to write. This is a reference, as defaults according to
* the schema may be filled in on the object, as well as ID on the serial
* type(s).
* @param update
* If this is an update, specify the primary keys' field names. It is the
* caller's responsibility to know if a record for this object already
* exists in the database. If there is only 1 key, you may pass a simple string.
* @return (boolean) Failure to write a record will return FALSE. Otherwise,
* TRUE is returned. The $object parameter contains values for any serial
* fields defined by the $table. For example, $object->nid will be populated
* after inserting a new node.
*/
function content_write_record($table, &$object, $update = array()) {
// Standardize $update to an array.
if (is_string($update)) {
$update = array($update);
}
// Convert to an object if needed.
if (is_array($object)) {
$object = (object) $object;
$array = TRUE;
}
else {
$array = FALSE;
}
$schema = drupal_get_schema($table);
if (empty($schema)) {
return FALSE;
}
$fields = $defs = $values = $serials = array();
// Go through our schema, build SQL, and when inserting, fill in defaults for
// fields that are not set.
foreach ($schema['fields'] as $field => $info) {
// Special case -- skip serial types if we are updating.
if ($info['type'] == 'serial' && count($update)) {
continue;
}
// For inserts, populate defaults from Schema if not already provided
if (!isset($object->$field) && !count($update) && isset($info['default'])) {
$object->$field = $info['default'];
}
// Track serial fields so we can helpfully populate them after the query.
if ($info['type'] == 'serial') {
$serials[] = $field;
// Ignore values for serials when inserting data. Unsupported.
$object->$field = 'NULL';
}
// Build arrays for the fields, placeholders, and values in our query.
if (isset($object->$field)) {
$fields[] = $field;
$placeholders[] = _db_type_placeholder($info['type']);
if (empty($info['serialize'])) {
$values[] = $object->$field;
}
else {
$values[] = serialize($object->$field);
}
}
}
// Build the SQL.
$query = '';
if (!count($update)) {
$query = "INSERT INTO {$table} (" . implode(', ', $fields) . ') VALUES (' . implode(', ', $placeholders) . ')';
}
else {
$query = '';
foreach ($fields as $id => $field) {
if ($query) {
$query .= ', ';
}
$query .= $field . ' = ' . $placeholders[$id];
}
foreach ($update as $key){
$conditions[] = "$key = ". _db_type_placeholder($schema['fields'][$key]['type']);
$query = "UPDATE {$table} SET $query WHERE ". implode(' AND ', $conditions);
$return = SAVED_UPDATED;
}
db_query($query, $values);
if ($serials) {
// Get last insert ids and fill them in.
foreach ($serials as $field) {
$object->$field = db_last_insert_id($table, $field);
}
}
// If we began with an array, convert back so we don't surprise the caller.
if ($array) {
$object = (array)$object;
}
return $return;
Jonathan Chaffer
committed
* Invoke a field hook.
Jonathan Chaffer
committed
*
* For each operation, both this function and _content_field_invoke_default() are
* called so that the default database handling can occur.
function _content_field_invoke($op, &$node, $teaser = NULL, $page = NULL) {
$type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
Jonathan Chaffer
committed
$type = content_types($type_name);
$field_types = _content_field_types();
$return = array();
Karen Stevenson
committed
if (count($type['fields'])) {
foreach ($type['fields'] as $field) {
$node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array();
Karen Stevenson
committed
$module = $field_types[$field['type']]['module'];
$function = $module .'_field';
if (function_exists($function)) {
$result = $function($op, $node, $field, $node_field, $teaser, $page);
Yves Chedemois
committed
if (is_array($result)) {
Karen Stevenson
committed
$return = array_merge($return, $result);
}
else if (isset($result)) {
$return[] = $result;
}
Karen Stevenson
committed
// test for values in $node_field in case modules added items on insert
if (isset($node->$field['field_name']) || count($node_field)) {
$node->$field['field_name'] = $node_field;
}
return $return;
}
/**
* Invoke content.module's version of a field hook.
*/
function _content_field_invoke_default($op, &$node, $teaser = NULL, $page = NULL) {
$type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
Jonathan Chaffer
committed
$type = content_types($type_name);
$return = array();
// The operations involving database queries are better off handled by table
// rather than by field.
if (in_array($op, array('load', 'insert', 'update', 'delete','delete revision'))) {
return content_storage($op, $node);
}
elseif (count($type['fields'])) {
Karen Stevenson
committed
foreach ($type['fields'] as $field) {
$node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array();
Karen Stevenson
committed
$db_info = content_database_info($field);
if (count($db_info['columns'])) {
Karen Stevenson
committed
$result = content_field($op, $node, $field, $node_field, $teaser, $page);
Yves Chedemois
committed
if (is_array($result)) {
Karen Stevenson
committed
$return = array_merge($return, $result);
}
else if (isset($result)) {
$return[] = $result;
}
Jonathan Chaffer
committed
}
Karen Stevenson
committed
if (isset($node->$field['field_name'])) {
$node->$field['field_name'] = $node_field;
Jonathan Chaffer
committed
}
Jonathan Chaffer
committed
}
Yves Chedemois
committed
* @param $content_type_name
Jonathan Chaffer
committed
* If set, return information on just this type.
*/
Karen Stevenson
committed
function content_types($type_name = NULL) {
// handle type name with either an underscore or a dash
$type_name = !empty($type_name) ? str_replace('-', '_', $type_name) : NULL;
Jonathan Chaffer
committed
$info = _content_type_info();
Karen Stevenson
committed
if (isset($type_name)) {
if (isset($info['content types'][$type_name])) {
return $info['content types'][$type_name];
Jonathan Chaffer
committed
}
else {
return NULL;
}
}
return $info['content types'];
}
/**
* Return a list of all fields.
*
* @param $field_name
* If set, return information on just this field.
* @param $content_type_name
* If set, return information of the field within the context of this content
* type.
Jonathan Chaffer
committed
*/
function content_fields($field_name = NULL, $content_type_name = NULL) {
Jonathan Chaffer
committed
$info = _content_type_info();
if (isset($field_name)) {
if (isset($info['fields'][$field_name])) {
if (isset($content_type_name)) {
if (isset($info['content types'][$content_type_name]['fields'][$field_name])) {
return $info['content types'][$content_type_name]['fields'][$field_name];
}
else {
return NULL;
}
}
else {
return $info['fields'][$field_name];
}
}
else {
return NULL;
}
}
Jonathan Chaffer
committed
return $info['fields'];
}
/**
* Return a list of field types.
*/
function _content_field_types() {
$info = _content_type_info();
return $info['field types'];
}
/**
* Return a list of widget types.
*/
function _content_widget_types() {
$info = _content_type_info();
return $info['widget types'];
}
/**
* Collate all information on content types, fields, and related structures.
*
* @param $reset
* If TRUE, clear the cache and fetch the information from the database again.
Jonathan Chaffer
committed
function _content_type_info($reset = FALSE) {
static $info;
Jonathan Chaffer
committed
if ($reset || !isset($info)) {
if ($cached = cache_get('content_type_info', 'cache_content')) {
Karen Stevenson
committed
$info = $cached->data;
Jonathan Chaffer
committed
$info = array(
'field types' => array(),
'widget types' => array(),
'fields' => array(),
'content types' => array(),
);
foreach (module_list() as $module) {
$module_field_types = module_invoke($module, 'field_info');
if ($module_field_types) {
foreach ($module_field_types as $name => $field_info) {
Jonathan Chaffer
committed
$info['field types'][$name] = $field_info;
$info['field types'][$name]['module'] = $module;
$info['field types'][$name]['formatters'] = array();
Jonathan Chaffer
committed
}
}
$module_widgets = module_invoke($module, 'widget_info');
if ($module_widgets) {
foreach ($module_widgets as $name => $widget_info) {
Jonathan Chaffer
committed
$info['widget types'][$name] = $widget_info;
$info['widget types'][$name]['module'] = $module;
}
}
Karen Stevenson
committed
}
foreach (module_list() as $module) {
$module_formatters = module_invoke($module, 'field_formatter_info');
if ($module_formatters) {
foreach ($module_formatters as $name => $formatter_info) {
foreach ($formatter_info['field types'] as $field_type) {
$info['field types'][$field_type]['formatters'][$name] = $formatter_info;
$info['field types'][$field_type]['formatters'][$name]['module'] = $module;
}
}
Jonathan Chaffer
committed
}
Yves Chedemois
committed
$field_result = db_query('SELECT * FROM {node_field}');
Jonathan Chaffer
committed
while ($field = db_fetch_array($field_result)) {
$global_settings = $field['global_settings'] ? unserialize($field['global_settings']) : array();
unset($field['global_settings']);
Karen Stevenson
committed
// Preventative error handling for PHP5 if field nodule hasn't created an arrray.
if (is_array($global_settings)) {
$field = array_merge($field, $global_settings);
}
Jonathan Chaffer
committed
$instance_info = db_fetch_array(db_query("SELECT type_name, label FROM {node_field_instance} WHERE field_name = '%s'", $field['field_name']));
$field['widget']['label'] = $instance_info['label'];
$field['type_name'] = $instance_info['type_name'];
$info['fields'][$field['field_name']] = $field;
}
Yves Chedemois
committed
$type_result = db_query('SELECT * FROM {node_type} ORDER BY type ASC');
Jonathan Chaffer
committed
while ($type = db_fetch_array($type_result)) {
Karen Stevenson
committed
$type['url_str'] = str_replace('_', '-', $type['type']);
Jonathan Chaffer
committed
$type['fields'] = array();
Yves Chedemois
committed
$field_result = db_query("SELECT * FROM {node_field_instance} nfi WHERE nfi.type_name = '%s' ORDER BY nfi.weight ASC, nfi.label ASC", $type['type']);
Jonathan Chaffer
committed
// Overwrite global field information with specific information
$field = array_merge($info['fields'][$field['field_name']], $field);
$widget_settings = $field['widget_settings'] ? unserialize($field['widget_settings']) : array();
unset($field['widget_settings']);
$field['widget'] = $widget_settings;
$field['widget']['type'] = $field['widget_type'];
unset($field['widget_type']);
$field['widget']['weight'] = $field['weight'];
unset($field['weight']);
$field['widget']['label'] = $field['label'];
unset($field['label']);
$field['widget']['description'] = $field['description'];
unset($field['description']);
Karen Stevenson
committed
$field['type_name'] = $type['type'];
Yves Chedemois
committed
$field['display_settings'] = $field['display_settings'] ? unserialize($field['display_settings']) : array();
Jonathan Chaffer
committed
$type['fields'][$field['field_name']] = $field;
$db_info = content_database_info($field);
$type['tables'][$db_info['table']] = $db_info['table'];
Karen Stevenson
committed
$info['content types'][$type['type']] = $type;
Karen Stevenson
committed
cache_set('content_type_info', $info, 'cache_content');
Jonathan Chaffer
committed
return $info;
}
Karen Stevenson
committed
/**
* Implementation of hook_node_type()
* React to change in node types
*/
function content_node_type($op, $info) {
switch ($op) {
Karen Stevenson
committed
module_load_include('inc', 'content', 'content_crud');
Karen Stevenson
committed
content_type_create($info);
break;
Karen Stevenson
committed
module_load_include('inc', 'content', 'content_crud');
Karen Stevenson
committed
content_type_update($info);
break;
Karen Stevenson
committed
module_load_include('inc', 'content', 'content_crud');