Code coverage for /20081101/modules/node/content_types.inc

Line #Times calledCode
1
<?php
2
// $Id: content_types.inc,v 1.58 2008/10/08 03:27:56 webchick Exp $
3
4
/**
5
 * @file
6
 * Content type editing UI.
7
 */
8
9
/**
10
 * Displays the content type admin overview page.
11
 */
1213
function node_overview_types() {
131
  $types = node_get_types();
141
  $names = node_get_types('names');
151
  $header = array(t('Name'), t('Type'), t('Description'), array('data' =>
t('Operations'), 'colspan' => '2'));
161
  $rows = array();
17
181
  foreach ($names as $key => $name) {
191
    $type = $types[$key];
201
    if (node_hook($type, 'form')) {
211
      $type_url_str = str_replace('_', '-', $type->type);
22
      $row = array(
231
        check_plain($name),
241
        check_plain($type->type),
251
        filter_xss_admin($type->description),
261
      );
27
      // Set the edit column.
281
      $row[] = array('data' => l(t('edit'), 'admin/build/node-type/' .
$type_url_str));
29
30
      // Set the delete column.
311
      if ($type->custom) {
321
        $row[] = array('data' => l(t('delete'), 'admin/build/node-type/' .
$type_url_str . '/delete'));
331
      }
34
      else {
350
        $row[] = array('data' => '');
36
      }
371
      $rows[] = $row;
381
    }
391
  }
40
411
  if (empty($rows)) {
420
    $rows[] = array(array('data' => t('No content types available.'),
'colspan' => '5', 'class' => 'message'));
430
  }
44
451
  return theme('table', $header, $rows);
460
}
47
48
/**
49
 * Generates the node type editing form.
50
 */
5113
function node_type_form(&$form_state, $type = NULL) {
523
  if (!isset($type->type)) {
53
    // This is a new type.  Node module managed types are custom and
unlocked.
540
    $type = node_type_set_defaults(array('custom' => 1, 'locked' => 0));
550
  }
56
57
  // Make the type object available to implementations of hook_form_alter.
583
  $form['#node_type'] = $type;
59
603
  $form['identity'] = array(
613
    '#type' => 'fieldset',
623
    '#title' => t('Identification'),
63
  );
643
  $form['identity']['name'] = array(
653
    '#title' => t('Name'),
663
    '#type' => 'textfield',
673
    '#default_value' => $type->name,
683
    '#description' => t('The human-readable name of this content type. This
text will be displayed as part of the list on the <em>create content</em>
page. It is recommended that this name begin with a capital letter and
contain only letters, numbers, and <strong>spaces</strong>. This name must
be unique.'),
693
    '#required' => TRUE,
70
  );
71
723
  if (!$type->locked) {
733
    $form['identity']['type'] = array(
743
      '#title' => t('Type'),
753
      '#type' => 'textfield',
763
      '#default_value' => $type->type,
773
      '#maxlength' => 32,
783
      '#required' => TRUE,
793
      '#description' => t('The machine-readable name of this content type.
This text will be used for constructing the URL of the <em>create
content</em> page for this content type. This name must contain only
lowercase letters, numbers, and underscores. Underscores will be converted
into hyphens when constructing the URL of the <em>create content</em> page.
This name must be unique.'),
80
    );
813
  }
82
  else {
830
    $form['identity']['type'] = array(
840
      '#type' => 'value',
850
      '#value' => $type->type,
86
    );
870
    $form['identity']['type_display'] = array(
880
      '#title' => t('Type'),
890
      '#type' => 'item',
900
      '#markup' => theme('placeholder', $type->type),
910
      '#description' => t('The machine-readable name of this content type.
This field cannot be modified for system-defined content types.'),
92
    );
93
  }
94
953
  $form['identity']['description'] = array(
963
    '#title' => t('Description'),
973
    '#type' => 'textarea',
983
    '#default_value' => $type->description,
993
    '#description' => t('A brief description of this content type. This
text will be displayed as part of the list on the <em>create content</em>
page.'),
100
    );
101
1023
  $form['submission'] = array(
1033
    '#type' => 'fieldset',
1043
    '#title' => t('Submission form settings'),
1053
    '#collapsible' => TRUE,
1063
    '#collapsed' => TRUE,
107
  );
1083
  $form['submission']['title_label'] = array(
1093
    '#title' => t('Title field label'),
1103
    '#type' => 'textfield',
1113
    '#default_value' => $type->title_label,
1123
    '#required' => TRUE,
113
  );
1143
  if (!$type->has_title) {
115
    // Avoid overwriting a content type that intentionally does not have a
116
    // title field.
1170
    $form['submission']['title_label']['#attributes'] = array('disabled' =>
'disabled');
1180
    $form['submission']['title_label']['#description'] = t('This content
type does not have a title field.');
1190
    $form['submission']['title_label']['#required'] = FALSE;
1200
  }
1213
  $form['submission']['body_label'] = array(
1223
    '#title' => t('Body field label'),
1233
    '#type' => 'textfield',
1243
    '#default_value' => isset($type->body_label) ? $type->body_label : '',
1253
    '#description' => t('To omit the body field for this content type,
remove any text and leave this field blank.'),
126
  );
1273
  $form['submission']['min_word_count'] = array(
1283
    '#type' => 'select',
1293
    '#title' => t('Minimum number of words'),
1303
    '#default_value' => $type->min_word_count,
1313
    '#options' => drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150,
175, 200)),
1323
    '#description' => t('The minimum number of words for the body field to
be considered valid for this content type. This can be useful to rule out
submissions that do not meet the site\'s standards, such as short test
posts.')
1333
  );
1343
  $form['submission']['help']  = array(
1353
    '#type' => 'textarea',
1363
    '#title' => t('Explanation or submission guidelines'),
1373
    '#default_value' => $type->help,
1383
    '#description' => t('This text will be displayed at the top of the
submission form for this content type. It is useful for helping or
instructing your users.')
1393
  );
1403
  $form['workflow'] = array(
1413
    '#type' => 'fieldset',
1423
    '#title' => t('Workflow settings'),
1433
    '#collapsible' => TRUE,
1443
    '#collapsed' => TRUE,
145
  );
1463
  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
1473
    '#title' => t('Default options'),
1483
    '#default_value' => variable_get('node_options_' . $type->type,
array('status', 'promote')),
149
    '#options' => array(
1503
      'status' => t('Published'),
1513
      'promote' => t('Promoted to front page'),
1523
      'sticky' => t('Sticky at top of lists'),
1533
      'revision' => t('Create new revision'),
1543
    ),
1553
    '#description' => t('Users with the <em>administer nodes</em>
permission will be able to override these options.'),
156
  );
157
1583
  $form['old_type'] = array(
1593
    '#type' => 'value',
1603
    '#value' => $type->type,
161
  );
1623
  $form['orig_type'] = array(
1633
    '#type' => 'value',
1643
    '#value' => isset($type->orig_type) ? $type->orig_type : '',
165
  );
1663
  $form['base'] = array(
1673
    '#type' => 'value',
1683
    '#value' => $type->base,
169
  );
1703
  $form['custom'] = array(
1713
    '#type' => 'value',
1723
    '#value' => $type->custom,
173
  );
1743
  $form['modified'] = array(
1753
    '#type' => 'value',
1763
    '#value' => $type->modified,
177
  );
1783
  $form['locked'] = array(
1793
    '#type' => 'value',
1803
    '#value' => $type->locked,
181
  );
182
1833
  $form['submit'] = array(
1843
    '#type' => 'submit',
1853
    '#value' => t('Save content type'),
1863
    '#weight' => 40,
187
  );
188
1893
  if ($type->custom) {
1903
    if (!empty($type->type)) {
1913
      $form['delete'] = array(
1923
        '#type' => 'submit',
1933
        '#value' => t('Delete content type'),
1943
        '#weight' => 45,
195
      );
1963
    }
1973
  }
198
  else {
1990
    $form['reset'] = array(
2000
      '#type' => 'submit',
2010
      '#value' => t('Reset to defaults'),
2020
      '#weight' => 50,
203
    );
204
  }
205
2063
  return $form;
2070
}
208
209
/**
210
 * Implementation of hook_form_validate().
211
 */
21213
function node_type_form_validate($form, &$form_state) {
2131
  $type = new stdClass();
2141
  $type->type = trim($form_state['values']['type']);
2151
  $type->name = trim($form_state['values']['name']);
216
217
  // Work out what the type was before the user submitted this form
2181
  $old_type = trim($form_state['values']['old_type']);
219
2201
  $types = node_get_types('names');
221
2221
  if (!$form_state['values']['locked']) {
2231
    if (isset($types[$type->type]) && $type->type != $old_type) {
2240
      form_set_error('type', t('The machine-readable name %type is already
taken.', array('%type' => $type->type)));
2250
    }
2261
    if (!preg_match('!^[a-z0-9_]+$!', $type->type)) {
2270
      form_set_error('type', t('The machine-readable name must contain only
lowercase letters, numbers, and underscores.'));
2280
    }
229
    // 'theme' conflicts with theme_node_form().
230
    // '0' is invalid, since elsewhere we check it using empty().
2311
    if (in_array($type->type, array('0', 'theme'))) {
2320
      form_set_error('type', t("Invalid machine-readable name. Please enter
a name other than %invalid.", array('%invalid' => $type->type)));
2330
    }
2341
  }
235
2361
  $names = array_flip($types);
237
2381
  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
2390
    form_set_error('name', t('The human-readable name %name is already
taken.', array('%name' => $type->name)));
2400
  }
2411
}
242
243
/**
244
 * Implementation of hook_form_submit().
245
 */
24613
function node_type_form_submit($form, &$form_state) {
2471
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] :
'';
248
2491
  $type = node_type_set_defaults();
250
2511
  $type->type = trim($form_state['values']['type']);
2521
  $type->name = trim($form_state['values']['name']);
2531
  $type->orig_type = trim($form_state['values']['orig_type']);
2541
  $type->old_type = isset($form_state['values']['old_type']) ?
$form_state['values']['old_type'] : $type->type;
255
2561
  $type->description = $form_state['values']['description'];
2571
  $type->help = $form_state['values']['help'];
2581
  $type->min_word_count = $form_state['values']['min_word_count'];
2591
  $type->title_label = $form_state['values']['title_label'];
2601
  $type->body_label = $form_state['values']['body_label'];
261
262
  // title_label is required in core; has_title will always be true, unless
a
263
  // module alters the title field.
2641
  $type->has_title = ($type->title_label != '');
2651
  $type->has_body = ($type->body_label != '');
266
2671
  $type->base = !empty($form_state['values']['base']) ?
$form_state['values']['base'] : 'node_content';
2681
  $type->custom = $form_state['values']['custom'];
2691
  $type->modified = TRUE;
2701
  $type->locked = $form_state['values']['locked'];
271
2721
  if ($op == t('Reset to defaults')) {
2730
    node_type_reset($type);
2740
  }
2751
  elseif ($op == t('Delete content type')) {
2760
    $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_',
'-', $type->old_type) . '/delete';
2770
    return;
2780
  }
279
2801
  $status = node_type_save($type);
281
2821
  $variables = $form_state['values'];
283
284
  // Remove everything that's been saved already - whatever's left is
assumed
285
  // to be a persistent variable.
2861
  foreach ($variables as $key => $value) {
2871
    if (isset($type->$key)) {
2881
      unset($variables[$key]);
2891
    }
2901
  }
291
2921
  unset($variables['form_token'], $variables['op'], $variables['submit'],
$variables['delete'], $variables['reset'], $variables['form_id']);
293
294
  // Save or reset persistent variable values.
2951
  foreach ($variables as $key => $value) {
2961
    $variable_new = $key . '_' . $type->type;
2971
    $variable_old = $key . '_' . $type->old_type;
298
2991
    if ($op == t('Reset to defaults')) {
3000
      variable_del($variable_old);
3010
    }
302
    else {
3031
      if (is_array($value)) {
3041
        $value = array_keys(array_filter($value));
3051
      }
3061
      variable_set($variable_new, $value);
307
3081
      if ($variable_new != $variable_old) {
3090
        variable_del($variable_old);
3100
      }
311
    }
3121
  }
313
3141
  node_types_rebuild();
3151
  menu_rebuild();
3161
  $t_args = array('%name' => $type->name);
317
3181
  if ($op == t('Reset to defaults')) {
3190
    drupal_set_message(t('The content type %name has been reset to its
default values.', $t_args));
3200
    return;
3210
  }
322
3231
  if ($status == SAVED_UPDATED) {
3241
    drupal_set_message(t('The content type %name has been updated.',
$t_args));
3251
  }
3260
  elseif ($status == SAVED_NEW) {
3270
    drupal_set_message(t('The content type %name has been added.',
$t_args));
3280
    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE,
l(t('view'), 'admin/build/types'));
3290
  }
330
3311
  $form_state['redirect'] = 'admin/build/types';
3321
  return;
3330
}
334
335
/**
336
 * Implementation of hook_node_type().
337
 */
33813
function node_node_type($op, $info) {
339135
  if ($op != 'delete' && !empty($info->old_type) && $info->old_type !=
$info->type) {
3400
    $update_count = node_type_update_nodes($info->old_type, $info->type);
341
3420
    if ($update_count) {
3430
      drupal_set_message(format_plural($update_count, 'Changed the content
type of 1 post from %old-type to %type.', 'Changed the content type of
@count posts from %old-type to %type.', array('%old-type' =>
$info->old_type, '%type' => $info->type)));
3440
    }
3450
  }
346135
}
347
348
/**
349
 * Resets all of the relevant fields of a module-defined node type to their
350
 * default values.
351
 *
352
 * @param &$type
353
 *   The node type to reset. The node type is passed back by reference with
its
354
 *   resetted values. If there is no module-defined info for this node
type,
355
 *   then nothing happens.
356
 */
35713
function node_type_reset(&$type) {
3580
  $info_array = module_invoke_all('node_info');
3590
  if (isset($info_array[$type->orig_type])) {
3600
    $info_array[$type->orig_type]['type'] = $type->orig_type;
3610
    $info = node_type_set_defaults($info_array[$type->orig_type]);
362
3630
    foreach ($info as $field => $value) {
3640
      $type->$field = $value;
3650
    }
3660
  }
3670
}
368
369
/**
370
 * Menu callback; delete a single content type.
371
 */
37213
function node_type_delete_confirm(&$form_state, $type) {
3730
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
3740
  $form['name'] = array('#type' => 'value', '#value' => $type->name);
375
3760
  $message = t('Are you sure you want to delete the content type %type?',
array('%type' => $type->name));
3770
  $caption = '';
378
3790
  $num_nodes = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type =
'%s'", $type->type));
3800
  if ($num_nodes) {
3810
    $caption .= '<p>' . format_plural($num_nodes,
'<strong>Warning:</strong> there is currently 1 %type post on your site. It
may not be able to be displayed or edited correctly, once you have removed
this content type.', '<strong>Warning:</strong> there are currently @count
%type posts on your site. They may not be able to be displayed or edited
correctly, once you have removed this content type.', array('%type' =>
$type->name)) . '</p>';
3820
  }
383
3840
  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
385
3860
  return confirm_form($form, $message, 'admin/build/types', $caption,
t('Delete'));
3870
}
388
389
/**
390
 * Process content type delete confirm submissions.
391
 */
39213
function node_type_delete_confirm_submit($form, &$form_state) {
3930
  node_type_delete($form_state['values']['type']);
394
3950
  $t_args = array('%name' => $form_state['values']['name']);
3960
  drupal_set_message(t('The content type %name has been deleted.',
$t_args));
3970
  watchdog('menu', 'Deleted content type %name.', $t_args,
WATCHDOG_NOTICE);
398
3990
  node_types_rebuild();
4000
  menu_rebuild();
401
4020
  $form_state['redirect'] = 'admin/build/types';
4030
  return;
4040
}
40513