| 1 |
<?php // -*-php-*-
|
| 2 |
// $Id: workflow_fields.module,v 1.5 2007/02/05 18:59:55 kratib Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* This module adds to workflow.module the ability to specify, for each state, which node fields should be visible and/or editable.
|
| 7 |
* It is a useful feature when workflows demand that certain information be hidden or read-only to certain roles.
|
| 8 |
*
|
| 9 |
* ISSUES AND LIMITATIONS
|
| 10 |
* 1. Only node editing is handled for invisible and read-only fields. Node viewing is not handled.
|
| 11 |
* 2. Only CCK node types are supported.
|
| 12 |
*
|
| 13 |
*/
|
| 14 |
|
| 15 |
/**
|
| 16 |
* Implementation of hook_help().
|
| 17 |
*/
|
| 18 |
function workflow_fields_help($section) {
|
| 19 |
switch ($section) {
|
| 20 |
case 'admin/modules#description':
|
| 21 |
return t('Add per-state CCK field settings to workflows. <em>Note: Requires both workflow.module and content.module</em>.');
|
| 22 |
}
|
| 23 |
}
|
| 24 |
|
| 25 |
/**
|
| 26 |
* Implementation of hook_form_alter().
|
| 27 |
* Hook on both any CCK node form and on the workflow state form.
|
| 28 |
*
|
| 29 |
* @param object &$node
|
| 30 |
* @return array
|
| 31 |
*/
|
| 32 |
function workflow_fields_form_alter($form_id, &$form) {
|
| 33 |
if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
|
| 34 |
workflow_fields_node_form_alter($form_id, $form);
|
| 35 |
} elseif ('workflow_state_add_form' == $form_id) {
|
| 36 |
workflow_fields_state_form_alter($form_id, $form);
|
| 37 |
}
|
| 38 |
}
|
| 39 |
|
| 40 |
/**
|
| 41 |
* Alter the workflow state form.
|
| 42 |
* Add a table listing the fields for workflow's content type.
|
| 43 |
*/
|
| 44 |
function workflow_fields_state_form_alter($form_id, &$form) {
|
| 45 |
$wid = $form['wid']['#value'];
|
| 46 |
$sid = $form['sid']['#value'];
|
| 47 |
|
| 48 |
// List all CCK fields for this workflow's content type.
|
| 49 |
$type = db_result(db_query("SELECT type FROM {workflow_type_map} WHERE wid=%d", $wid));
|
| 50 |
if (!$type) return;
|
| 51 |
if (module_exists('content') && ($content = content_types($type))) {
|
| 52 |
$fields = $content['fields'];
|
| 53 |
$form['submit_chain'] = array('#type' => 'value', '#value' => $form['#submit']);
|
| 54 |
$form['#submit'] = array('workflow_fields_state_form_submit' => array());
|
| 55 |
$form['fields'] = array();
|
| 56 |
$form['fields']['type'] = array('#type' => 'value', '#value' => $type);
|
| 57 |
$form['fields']['#theme'] = 'workflow_fields_state';
|
| 58 |
$form['fields']['#tree'] = TRUE;
|
| 59 |
foreach($fields as $field) {
|
| 60 |
$values = db_fetch_array(db_query("SELECT visible, editable FROM {workflow_fields} WHERE sid = %d AND name = '%s'", intval($sid), $field['field_name']));
|
| 61 |
$form['fields'][$field['field_name']]['visible'] = array(
|
| 62 |
'#type' => 'checkbox',
|
| 63 |
'#default_value' => isset($values['visible']) ? $values['visible'] : TRUE,
|
| 64 |
'#attributes' => array('onchange' => 'javascript:document.getElementById("'.form_clean_id('edit-fields-'.$field['field_name'].'-editable').'").disabled=!this.checked;',
|
| 65 |
'onclick' => 'javascript:document.getElementById("'.form_clean_id('edit-fields-'.$field['field_name'].'-editable').'").disabled=!this.checked;'),
|
| 66 |
);
|
| 67 |
$form['fields'][$field['field_name']]['editable'] = array(
|
| 68 |
'#type' => 'checkbox',
|
| 69 |
'#default_value' => isset($values['editable']) ? $values['editable'] : TRUE,
|
| 70 |
'#attributes' => $form['fields'][$field['field_name']]['visible']['#default_value'] ? array() : array('disabled' => 'disabled'),
|
| 71 |
);
|
| 72 |
}
|
| 73 |
} else {
|
| 74 |
watchdog('workflow fields', t('The content type "%type" does not provide metadata information.', array('%type' => $type)));
|
| 75 |
}
|
| 76 |
$form['submit']['#weight'] = 99;
|
| 77 |
}
|
| 78 |
|
| 79 |
function theme_workflow_fields_state($form) {
|
| 80 |
$type = $form['type']['#value'];
|
| 81 |
$content = content_types($type);
|
| 82 |
$fields = $content['fields'];
|
| 83 |
$header = array(t('Field name'), t('Visible'), t('Editable'));
|
| 84 |
$rows = array();
|
| 85 |
foreach($fields as $field) {
|
| 86 |
$rows[] = array($field['widget']['label'].' ('.$field['field_name'].')', drupal_render($form[$field['field_name']]['visible']), drupal_render($form[$field['field_name']]['editable']));
|
| 87 |
}
|
| 88 |
$output = theme('table', $header, $rows).'<p />';
|
| 89 |
return $output;
|
| 90 |
}
|
| 91 |
|
| 92 |
function workflow_fields_state_form_submit($form_id, $form_values) {
|
| 93 |
if (isset($form_values['fields'])) {
|
| 94 |
db_query("DELETE FROM {workflow_fields} WHERE sid = %d", intval($form_values['sid']));
|
| 95 |
foreach($form_values['fields'] as $key => $field) {
|
| 96 |
if ($key != 'type') {
|
| 97 |
db_query("INSERT INTO {workflow_fields} (sid, name, type, visible, editable) VALUES (%d, '%s', '%s', %d, %d)", $form_values['sid'], $key, $form_values['fields']['type'], $field['visible'], $field['editable']);
|
| 98 |
}
|
| 99 |
}
|
| 100 |
}
|
| 101 |
return _workflow_submit_form($form_id, $form_values);
|
| 102 |
}
|
| 103 |
|
| 104 |
/**
|
| 105 |
* Alter the node form by hiding/disabling fields depending on the workflow state.
|
| 106 |
* To hide a field, just unset it from the form.
|
| 107 |
* To disable a field, replace its form element by a view-only version (by calling the 'view' CCK function).
|
| 108 |
*/
|
| 109 |
function workflow_fields_node_form_alter($form_id, &$form) {
|
| 110 |
$node = $form['#node'];
|
| 111 |
$current = workflow_node_current_state($node);
|
| 112 |
|
| 113 |
// check for visible/editable flags
|
| 114 |
if (module_exists('content') && ($content = content_types($node->type))) {
|
| 115 |
$form['sid'] = array('#type' => 'value', '#value' => intval($current));
|
| 116 |
$form['submit_chain'] = array('#type' => 'value', '#value' => $form['#submit']);
|
| 117 |
$form['#submit'] = array('workflow_fields_node_form_submit' => array());
|
| 118 |
$result = db_query("SELECT * FROM {workflow_fields} WHERE sid = %d AND type = '%s' AND (visible=0 OR editable=0)", intval($current), $node->type);
|
| 119 |
while ($row = db_fetch_array($result)) {
|
| 120 |
if (!isset($form[$row['name']])) {
|
| 121 |
watchdog('workflow fields', t('Could not find field "%name" while altering the form', array('%name' => $row['name'])));
|
| 122 |
continue;
|
| 123 |
}
|
| 124 |
$field = $content['fields'][$row['name']];
|
| 125 |
if (!$row['visible']) {
|
| 126 |
$form[$row['name']] = array_merge($form[$row['name']], array('#access' => FALSE));
|
| 127 |
} elseif (!$row['editable']) {
|
| 128 |
$weight = $form[$row['name']]['#weight'];
|
| 129 |
$node_field = isset($node->$row['name']) ? $node->$row['name'] : array();
|
| 130 |
$form[$row['name']] = array(
|
| 131 |
'#type' => 'markup',
|
| 132 |
'#value' => _workflow_fields_node_view($node, $field, $node_field),
|
| 133 |
'#weight' => $weight,
|
| 134 |
);
|
| 135 |
}
|
| 136 |
}
|
| 137 |
}
|
| 138 |
}
|
| 139 |
|
| 140 |
/**
|
| 141 |
* Process CCK node submission.
|
| 142 |
* First load the original node before saving, then invoke the chain of hooks, then overwrite the hidden/disabled fields with their original values.
|
| 143 |
*/
|
| 144 |
function workflow_fields_node_form_submit($form_id, $form_values) {
|
| 145 |
$nid = $form_values['nid'];
|
| 146 |
$result = db_query("SELECT name FROM {workflow_fields} WHERE sid = %d AND type = '%s' AND (visible=0 OR editable=0)", $form_values['sid'], $form_values['type']);
|
| 147 |
if (!is_null($nid) && db_num_rows($result) > 0) {
|
| 148 |
$original_node = node_load($nid);
|
| 149 |
}
|
| 150 |
|
| 151 |
// Let the node be saved before we restore the original values.
|
| 152 |
$goto = _workflow_submit_form($form_id, $form_values);
|
| 153 |
|
| 154 |
// Restore the field values that were hidden.
|
| 155 |
if (!is_null($nid) && db_num_rows($result) > 0) {
|
| 156 |
$node = node_load(array('nid' => $nid)); // Force node.module to load the node from database instead of cache
|
| 157 |
while ($row = db_fetch_array($result)) {
|
| 158 |
$node->$row['name'] = $original_node->$row['name'];
|
| 159 |
}
|
| 160 |
node_save($node);
|
| 161 |
}
|
| 162 |
|
| 163 |
return $goto;
|
| 164 |
}
|
| 165 |
|
| 166 |
/**
|
| 167 |
* Render a single field.
|
| 168 |
* This function is a copy of cck/content.module:_content_field_view.
|
| 169 |
*/
|
| 170 |
function _workflow_fields_node_view($node, $field, $node_field) {
|
| 171 |
$field_types = _content_field_types();
|
| 172 |
$teaser = FALSE;
|
| 173 |
$page = FALSE;
|
| 174 |
$context = 'full';
|
| 175 |
$formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default';
|
| 176 |
$value = '';
|
| 177 |
|
| 178 |
if ($formatter != 'hidden') {
|
| 179 |
if (content_handle('field', 'view', $field) == CONTENT_CALLBACK_CUSTOM) {
|
| 180 |
$module = $field_types[$field['type']]['module'];
|
| 181 |
$function = $module .'_field';
|
| 182 |
if (function_exists($function)) {
|
| 183 |
$value = $function('view', $node, $field, $node_field, $teaser, $page);
|
| 184 |
}
|
| 185 |
}
|
| 186 |
else {
|
| 187 |
foreach ($node_field as $delta => $item) {
|
| 188 |
$node_field[$delta]['view'] = content_format($field, $item, $formatter, $node);
|
| 189 |
}
|
| 190 |
$value = theme('field', $node, $field, $node_field, $teaser, $page);
|
| 191 |
}
|
| 192 |
}
|
| 193 |
|
| 194 |
return $value;
|
| 195 |
}
|
| 196 |
|
| 197 |
function _workflow_submit_form($form_id, $form_values) {
|
| 198 |
// Taken from /includes/form.inc:drupal_submit_form() except with different params.
|
| 199 |
$default_args = array($form_id, &$form_values);
|
| 200 |
if (isset($form_values['submit_chain'])) {
|
| 201 |
foreach ($form_values['submit_chain'] as $function => $args) {
|
| 202 |
if (function_exists($function)) {
|
| 203 |
$args = array_merge($default_args, (array) $args);
|
| 204 |
// Since we can only redirect to one page, only the last redirect will work
|
| 205 |
$redirect = call_user_func_array($function, $args);
|
| 206 |
if (isset($redirect)) {
|
| 207 |
$goto = $redirect;
|
| 208 |
}
|
| 209 |
}
|
| 210 |
}
|
| 211 |
}
|
| 212 |
return $goto;
|
| 213 |
}
|
| 214 |
|
| 215 |
?>
|