[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/cck/modules/fieldgroup/ -> fieldgroup.module (source)

   1  <?php
   2  // $Id: fieldgroup.module,v 1.79.2.53 2011/01/03 11:03:47 yched Exp $
   3  
   4  /**
   5   * @file
   6   * Create field groups for CCK fields.
   7   *
   8   * Hooks for other modules to intervene include:
   9   * - hook_fieldgroup_view: Alter the group $element added to $node->content.
  10   * - hook_fieldgroup_form: Alter the group portion of the node form.
  11   * - hook_fieldgroup_types: Add additional fieldgroup group_types.
  12   * - hook_fieldgroup_default_settings: Add additional fieldgroup default settings.
  13   * - hook_fieldgroup_save: Do additional processing when a fieldgroup is saved.
  14   */
  15  /**
  16   * Implementation of hook_init().
  17   */
  18  function fieldgroup_init() {
  19    drupal_add_css(drupal_get_path('module', 'fieldgroup') .'/fieldgroup.css');
  20  }
  21  
  22  /**
  23   * Implementation of hook_ctools_plugin_directory().
  24   */
  25  function fieldgroup_ctools_plugin_directory($module, $plugin) {
  26    if ($module == 'ctools' && $plugin == 'content_types') {
  27      return 'panels/' . $plugin;
  28    }
  29  }
  30  
  31  /**
  32   * Implementation of hook_menu().
  33   */
  34  function fieldgroup_menu() {
  35    $items = array();
  36  
  37    // Make sure this doesn't fire until content_types is working,
  38    // needed to avoid errors on initial installation.
  39    if (!defined('MAINTENANCE_MODE')) {
  40      foreach (node_get_types() as $type) {
  41        $type_name = $type->type;
  42        $content_type = content_types($type_name);
  43        $type_url_str = $content_type['url_str'];
  44        $items['admin/content/node-type/'. $type_url_str .'/groups/%'] = array(
  45          'title' => 'Edit group',
  46          'page callback' => 'drupal_get_form',
  47          'page arguments' => array('fieldgroup_group_edit_form', $type_name, 5),
  48          'access arguments' => array('administer content types'),
  49          'type' => MENU_CALLBACK,
  50        );
  51        $items['admin/content/node-type/'. $type_url_str .'/groups/%/remove'] = array(
  52          'title' => 'Edit group',
  53          'page callback' => 'drupal_get_form',
  54          'page arguments' => array('fieldgroup_remove_group', $type_name, 5),
  55          'access arguments' => array('administer content types'),
  56          'type' => MENU_CALLBACK,
  57        );
  58      }
  59    }
  60    return $items;
  61  }
  62  
  63  /**
  64   * Implementation of hook_theme().
  65   */
  66  function fieldgroup_theme() {
  67    return array(
  68      'fieldgroup_simple' => array(
  69        'template' => 'fieldgroup-simple',
  70        'arguments' => array('element' => NULL),
  71      ),
  72      'fieldgroup_fieldset' => array(
  73        'arguments' => array('element' => NULL),
  74      ),
  75      'fieldgroup_display_overview_form' => array(
  76        'arguments' => array('form' => NULL),
  77      ),
  78    );
  79  }
  80  
  81  /**
  82   * Implementation of hook_elements().
  83   */
  84  function fieldgroup_elements() {
  85    return array(
  86      'fieldgroup_simple' => array(),
  87      'fieldgroup_fieldset' => array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL,),
  88    );
  89  }
  90  
  91  /**
  92   * Implementation of hook_fieldapi().
  93   */
  94  function fieldgroup_content_fieldapi($op, $field) {
  95    switch ($op) {
  96      case 'delete instance':
  97        db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE field_name = '%s' AND type_name = '%s'", $field['field_name'], $field['type_name']);
  98        cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
  99        break;
 100    }
 101  }
 102  
 103  function fieldgroup_group_edit_form(&$form_state, $type_name, $group_name) {
 104    $content_type = content_types($type_name);
 105    $groups = fieldgroup_groups($content_type['type']);
 106  
 107    if (!$group = $groups[$group_name]) {
 108      drupal_not_found();
 109      exit;
 110    }
 111  
 112    $form['label'] = array(
 113      '#type' => 'textfield',
 114      '#title' => t('Label'),
 115      '#default_value' => $group['label'],
 116      '#required' => TRUE,
 117    );
 118  
 119    // Set a default value for group type early in the form so it
 120    // can be overridden by subsequent form elements added by other modules.
 121    $group_type = !empty($group['group_type']) ? $group['group_type'] : 'standard';
 122    $form['group_type'] = array('#type' => 'hidden', '#default_value' => $group_type);
 123  
 124    $form['settings']['#tree'] = TRUE;
 125    $form['settings']['form'] = array(
 126      '#type' => 'fieldset',
 127      '#title' => t('Form settings'),
 128      '#description' => t('These settings apply to the group in the node editing form.'),
 129    );
 130    $form['settings']['form']['style'] = array(
 131      '#type' => 'radios',
 132      '#title' => t('Style'),
 133      '#default_value' => $group['settings']['form']['style'],
 134      '#options' => array(
 135        'fieldset' => t('always open'),
 136        'fieldset_collapsible' => t('collapsible'),
 137        'fieldset_collapsed' => t('collapsed'),
 138      )
 139    );
 140    $form['settings']['form']['description'] = array(
 141      '#type' => 'textarea',
 142      '#title' => t('Help text'),
 143      '#default_value' => $group['settings']['form']['description'],
 144      '#rows' => 5,
 145      '#description' => t('Instructions to present to the user on the editing form.'),
 146      '#required' => FALSE,
 147    );
 148    $form['settings']['display'] = array(
 149      '#type' => 'fieldset',
 150      '#title' => t('Display settings'),
 151      '#description' => t('These settings apply to the group on node display.'),
 152    );
 153    $form['settings']['display']['description'] = array(
 154      '#type' => 'textarea',
 155      '#title' => t('Description'),
 156      '#default_value' => $group['settings']['display']['description'],
 157      '#rows' => 5,
 158      '#description' => t('A description of the group.'),
 159      '#required' => FALSE,
 160    );
 161  
 162    foreach (array_keys(content_build_modes()) as $key) {
 163      $form['settings']['display'][$key]['format'] = array('#type' => 'value', '#value' => isset($group['settings']['display'][$key]['format']) ? $group['settings']['display'][$key]['format'] : 'fieldset');
 164      $form['settings']['display'][$key]['exclude'] = array('#type' => 'value', '#value' => isset($group['settings']['display'][$key]['exclude']) ? $group['settings']['display'][$key]['exclude'] : 0);
 165    }
 166    $form['settings']['display']['label'] = array('#type' => 'value', '#value' => $group['settings']['display']['label']);
 167    $form['weight'] = array('#type' => 'hidden', '#default_value' => $group['weight']);
 168    $form['group_name'] = array('#type' => 'hidden', '#default_value' => $group_name);
 169  
 170    $form['#content_type'] = $content_type;
 171  
 172    $form['submit'] = array(
 173      '#type' => 'submit',
 174      '#value' => t('Save'),
 175      '#weight' => 10,
 176    );
 177  
 178    return $form;
 179  }
 180  
 181  function fieldgroup_group_edit_form_submit($form, &$form_state) {
 182    $form_values = $form_state['values'];
 183    $content_type = $form['#content_type'];
 184    fieldgroup_save_group($content_type['type'], $form_values);
 185    $form_state['redirect'] = 'admin/content/node-type/'. $content_type['url_str'] .'/fields';
 186  }
 187  
 188  function fieldgroup_remove_group(&$form_state, $type_name, $group_name) {
 189    $content_type = content_types($type_name);
 190    $groups = fieldgroup_groups($content_type['type']);
 191    $group = isset($groups[$group_name]) ? $groups[$group_name] : '';
 192  
 193    if (empty($group)) {
 194      drupal_not_found();
 195      exit;
 196    }
 197  
 198    $form['#submit'][] = 'fieldgroup_remove_group_submit';
 199    $form['#content_type'] = $content_type;
 200    $form['#group_name'] = $group_name;
 201  
 202    return confirm_form($form,
 203                    t('Are you sure you want to remove the group %label?',
 204                    array('%label' => t($group['label']))),
 205                    'admin/content/node-type/'. $content_type['url_str'] .'/fields', t('This action cannot be undone.'),
 206                    t('Remove'), t('Cancel'));
 207  }
 208  
 209  function fieldgroup_remove_group_submit($form, &$form_state) {
 210    $form_values = $form_state['values'];
 211    $content_type = $form['#content_type'];
 212    $group_name = $form['#group_name'];
 213    fieldgroup_delete($content_type['type'], $group_name);
 214    drupal_set_message(t('The group %group_name has been removed.', array('%group_name' => $group_name)));
 215    $form_state['redirect'] = 'admin/content/node-type/'. $content_type['url_str'] .'/fields';
 216  }
 217  
 218  /**
 219   * Returns all groups for a content type
 220   */
 221  function fieldgroup_groups($content_type = '', $sorted = FALSE, $reset = FALSE) {
 222    global $language;
 223    static $groups, $groups_sorted;
 224    if (!isset($groups) || $reset) {
 225      if ($cached = cache_get('fieldgroup_data:'. $language->language, content_cache_tablename())) {
 226        $data = $cached->data;
 227        $groups = $data['groups'];
 228        $groups_sorted = $data['groups_sorted'];
 229      }
 230      else {
 231        $result = db_query("SELECT * FROM {". fieldgroup_tablename() ."} ORDER BY weight, group_name");
 232        $groups = array();
 233        $groups_sorted = array();
 234        while ($group = db_fetch_array($result)) {
 235          $group['settings'] = unserialize($group['settings']);
 236          $group['fields'] = array();
 237  
 238          // Allow external modules to translate field group strings.
 239          $group_strings = array(
 240            'label' => $group['label'],
 241            'form_description' => $group['settings']['form']['description'],
 242            'display_description' => $group['settings']['display']['description'],
 243          );
 244          drupal_alter('content_fieldgroup_strings', $group_strings, $group['type_name'], $group['group_name']);
 245          $group['label'] = $group_strings['label'];
 246          $group['settings']['form']['description'] = $group_strings['form_description'];
 247          $group['settings']['display']['description'] = $group_strings['display_description'];
 248  
 249          $groups[$group['type_name']][$group['group_name']] = $group;
 250          $groups_sorted[$group['type_name']][] = &$groups[$group['type_name']][$group['group_name']];
 251        }
 252        //load fields
 253        $result = db_query("SELECT nfi.*, ng.group_name FROM {". fieldgroup_tablename() ."} ng ".
 254   "INNER JOIN {". fieldgroup_fields_tablename() ."} ngf ON ngf.type_name = ng.type_name AND ngf.group_name = ng.group_name ".
 255   "INNER JOIN {". content_instance_tablename() ."} nfi ON nfi.field_name = ngf.field_name AND nfi.type_name = ngf.type_name ".
 256   "WHERE nfi.widget_active = 1 ORDER BY nfi.weight");
 257        while ($field = db_fetch_array($result)) {
 258          // Allow external modules to translate field strings.
 259          $field_strings = array(
 260            'widget_label' => $field['label'],
 261            'widget_description' => $field['description'],
 262          );
 263          drupal_alter('content_field_strings', $field_strings, $field['type_name'], $field['field_name']);
 264          $field['label'] = $field_strings['widget_label'];
 265          $field['description'] = $field_strings['widget_description'];
 266  
 267          $groups[$field['type_name']][$field['group_name']]['fields'][$field['field_name']] = $field;
 268        }
 269        cache_set('fieldgroup_data:'. $language->language, array('groups' => $groups, 'groups_sorted' => $groups_sorted), content_cache_tablename());
 270      }
 271    }
 272    if (empty($content_type)) {
 273      return $groups;
 274    }
 275    elseif (empty($groups) || empty($groups[$content_type])) {
 276      return array();
 277    }
 278    return $sorted ? $groups_sorted[$content_type] : $groups[$content_type];
 279  }
 280  
 281  
 282  function _fieldgroup_groups_label($content_type) {
 283    $groups = fieldgroup_groups($content_type);
 284  
 285    $labels[''] = '<'. t('none') .'>';
 286    foreach ($groups as $group_name => $group) {
 287      $labels[$group_name] = t($group['label']);
 288    }
 289    return $labels;
 290  }
 291  
 292  function _fieldgroup_field_get_group($content_type, $field_name) {
 293    return db_result(db_query("SELECT group_name FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $content_type, $field_name));
 294  }
 295  
 296  /**
 297   * Implementation of hook_form_alter()
 298   */
 299  function fieldgroup_form_alter(&$form, $form_state, $form_id) {
 300    if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
 301      foreach (fieldgroup_groups($form['type']['#value']) as $group_name => $group) {
 302        $form[$group_name] = array(
 303          '#type' => 'fieldset',
 304          '#title' => check_plain(t($group['label'])),
 305          '#collapsed' => $group['settings']['form']['style'] == 'fieldset_collapsed',
 306          '#collapsible' => in_array($group['settings']['form']['style'], array('fieldset_collapsed', 'fieldset_collapsible')),
 307          '#weight' => $group['weight'],
 308          '#description' => content_filter_xss(t($group['settings']['form']['description'])),
 309          '#attributes' => array('class' => strtr($group['group_name'], '_', '-')),
 310        );
 311  
 312        $has_accessible_field = FALSE;
 313        foreach ($group['fields'] as $field_name => $field) {
 314          if (isset($form[$field_name])) {
 315            $form[$group_name][$field_name] = $form[$field_name];
 316            // Track whether this group has any accessible fields within it.
 317            if (!isset($form[$field_name]['#access']) || $form[$field_name]['#access'] !== FALSE) {
 318              $has_accessible_field = TRUE;
 319            }
 320            unset($form[$field_name]);
 321          }
 322        }
 323        if (!empty($group['fields']) && !element_children($form[$group_name])) {
 324          //hide the fieldgroup, because the fields are hidden too
 325          unset($form[$group_name]);
 326        }
 327  
 328        if (!$has_accessible_field) {
 329          // Hide the fieldgroup, because the fields are inaccessible.
 330          $form[$group_name]['#access'] = FALSE;
 331        }
 332  
 333        // Allow other modules to alter the form.
 334        // Can't use module_invoke_all because we want
 335        // to be able to use a reference to $form and $form_state.
 336        foreach (module_implements('fieldgroup_form') as $module) {
 337          $function = $module .'_fieldgroup_form';
 338          $function($form, $form_state, $form_id, $group);
 339        }
 340  
 341      }
 342  
 343    }
 344    // The group is only added here so it will appear in the export
 345    // when using Content Copy.
 346    elseif ($form_id == 'content_field_edit_form' && isset($form['widget'])) {
 347      $content_type = content_types($form['type_name']['#value']);
 348      $form['widget']['group'] = array(
 349        '#type' => 'value',
 350        '#value' => _fieldgroup_field_get_group($content_type['type'], $form['field_name']['#value']),
 351      );
 352    }
 353    elseif ($form_id == 'content_field_overview_form') {
 354      $form['#validate'][] = 'fieldgroup_field_overview_form_validate';
 355      $form['#submit'][] = 'fieldgroup_field_overview_form_submit';
 356    }
 357    elseif ($form_id == 'content_display_overview_form' && !empty($form['#groups'])) {
 358      $form['#submit'][] = 'fieldgroup_display_overview_form_submit';
 359      if (!isset($form['submit'])) {
 360        $form['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#weight' => 10);
 361      }
 362    }
 363    elseif ($form_id == 'content_field_remove_form') {
 364      $form['#submit'][] = 'fieldgroup_field_remove_form_submit';
 365    }
 366  }
 367  
 368  /**
 369   * API for group name validation.
 370   *
 371   * Pulled into separate function to be re-usable.
 372   */
 373  function fieldgroup_validate_name($group, $type_name) {
 374    $errors = array();
 375  
 376    // No label.
 377    if (!$group['label']) {
 378      $errors['label'][] = t('You need to provide a label.');
 379    }
 380  
 381    // No group name.
 382    if (!$group['group_name']) {
 383      $errors['group_name'][] = t('You need to provide a group name.');
 384    }
 385    // Group name validation.
 386    else {
 387      $group_name = $group['group_name'];
 388      $group['group_type'] = !empty($group['group_type']) ? $group['group_type'] : 'standard';
 389  
 390      // Add the 'group_' prefix.
 391      if (substr($group_name, 0, 6) != 'group_') {
 392        $group_name = 'group_'. $group_name;
 393      }
 394  
 395      // Invalid field name.
 396      if (!preg_match('!^group_[a-z0-9_]+$!', $group_name)) {
 397        $errors['group_name'][] = t('The group name %group_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%group_name' => $group_name));
 398      }
 399      if (strlen($group_name) > 32) {
 400        $errors['group_name'][] = t('The group name %group_name is too long. The name is limited to 32 characters, including the \'group_\' prefix.', array('%group_name' => $group_name));
 401      }
 402  
 403      // Group name already exists.
 404      $groups = fieldgroup_groups($type_name);
 405      if (isset($groups[$group_name])) {
 406        $errors['group_name'][] = t('The group name %group_name already exists.', array('%group_name' => $group_name));
 407      }
 408      if (empty($errors['group_name'])) {
 409        $group['group_name'] = $group_name;
 410      }
 411    }
 412    return array('group_name' => $group['group_name'], 'errors' => $errors);
 413  }
 414  
 415  function fieldgroup_field_overview_form_validate($form, &$form_state) {
 416    $form_values = $form_state['values'];
 417    $group = $form_values['_add_new_group'];
 418  
 419    if (array_filter(array($group['label'], $group['group_name']))) {
 420      $validation = fieldgroup_validate_name($group, $form['#type_name']);
 421      if (!empty($validation['errors'])) {
 422        foreach ($validation['errors'] as $type => $messages) {
 423          foreach ($messages as $message) {
 424            if ($type == 'label') {
 425              form_set_error('_add_new_group][label', t('Add new group:') .' '. $message);
 426            }
 427            else {
 428              form_set_error('_add_new_group][group_name', t('Add new group:') .' '. $message);
 429            }
 430          }
 431        }
 432      }
 433      $group_name = $validation['group_name'];
 434      form_set_value($form['_add_new_group']['group_name'], $group_name, $form_state);
 435    }
 436    else {
 437      // Fail validation if attempt to nest fields under a new group without the
 438      // proper information. Not raising an error would cause the nested fields
 439      // to get weights the user doesn't expect.
 440  
 441      foreach ($form_values as $key => $values) {
 442        if ($values['parent'] == '_add_new_group') {
 443          form_set_error('_add_new_group][label', t('Add new group: you need to provide a label.'));
 444          form_set_error('_add_new_group][group_name', t('Add new group: you need to provide a group name.'));
 445          break;
 446        }
 447      }
 448    }
 449  }
 450  
 451  function fieldgroup_field_overview_form_submit($form, &$form_state) {
 452    $form_values = $form_state['values'];
 453    $type_name = $form['#type_name'];
 454  
 455    // Create new group if needed.
 456    if (!empty($form_values['_add_new_group']['label'])) {
 457      $group = $form_values['_add_new_group'];
 458      $group['settings'] = field_group_default_settings($group['group_type']);
 459      fieldgroup_save_group($type_name, $group);
 460      $new_group_name = $group['group_name'];
 461    }
 462  
 463    // Parse incoming rows.
 464    $add_field_rows = array('_add_new_field', '_add_existing_field');
 465    $field_rows = array_merge($form['#fields'], $add_field_rows);
 466    foreach ($form_values as $key => $values) {
 467      // If 'field' row: update field parenting.
 468      if (in_array($key, $field_rows)) {
 469        // If newly added fields were added to a group:
 470        if (in_array($key, $add_field_rows)) {
 471          // We replace the '_add_*_field' key with the actual name of
 472          // the field that got added.
 473          // content_field_overview_form_submit() placed those
 474          // in $form_state['fields_added'] for us.
 475          if (isset($form_state['fields_added'][$key])) {
 476            $key = $form_state['fields_added'][$key];
 477          }
 478          else {
 479            // No field was actually created : skip to next row.
 480            continue;
 481          }
 482        }
 483        // If the field was added to the newly created group, replace the
 484        // '_add_new_group' value with the actual name of the group.
 485        $parent = ($values['parent'] == '_add_new_group' && isset($new_group_name)) ? $new_group_name : $values['parent'];
 486        // TODO: check the parent group does exist ?
 487        fieldgroup_update_fields(array('field_name' => $key, 'group' => $parent, 'type_name' => $type_name));
 488      }
 489  
 490      // If 'group' row:  update groups weights
 491      // (possible newly created group has already been taken care of).
 492      elseif (in_array($key, $form['#groups'])) {
 493        db_query("UPDATE {". fieldgroup_tablename() ."} SET weight = %d WHERE type_name = '%s' AND group_name = '%s'",
 494          $values['weight'], $type_name, $key);
 495      }
 496    }
 497  
 498    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 499  }
 500  
 501  function field_group_default_settings($group_type) {
 502    $settings = array(
 503      'form' => array('style' => 'fieldset', 'description' => ''),
 504      'display' => array('description' => '', 'label' => 'above'),
 505    );
 506    module_load_include('inc', 'content', 'includes/content.admin');
 507    foreach (array_keys(content_build_modes()) as $key) {
 508      $settings['display'][$key]['format'] = 'fieldset';
 509      $settings['display'][$key]['exclude'] = 0;
 510    }
 511    // Allow other modules to add new default settings.
 512    $settings = array_merge($settings, module_invoke_all('fieldgroup_default_settings', $group_type));
 513    return $settings;
 514  }
 515  
 516  function fieldgroup_display_overview_form_submit($form, &$form_state) {
 517    $form_values = $form_state['values'];
 518    $groups = fieldgroup_groups($form['#type_name']);
 519    foreach ($form_values as $key => $values) {
 520      if (in_array($key, $form['#groups'])) {
 521        $group = $groups[$key];
 522        // We have some numeric keys here, so we can't use array_merge.
 523        $group['settings']['display'] = $values + $group['settings']['display'];
 524        fieldgroup_save_group($form['#type_name'], $group);
 525      }
 526    }
 527  }
 528  
 529  function fieldgroup_field_remove_form_submit($form, &$form_state) {
 530    $form_values = $form_state['values'];
 531    // TODO:
 532    // - when a (non last) field is removed from a group, a 'ghost row' remains in the fields overview
 533    // - when the last field is removed, the group disappears
 534    // seems to be fixed when emptying the cache.
 535    db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']);
 536  }
 537  
 538  /**
 539   * Implementation of hook_nodeapi().
 540   */
 541  function fieldgroup_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
 542    switch ($op) {
 543      case 'view':
 544        // Prevent against invalid 'nodes' built by broken 3rd party code.
 545        if (isset($node->type)) {
 546          // Build the node content element needed to render each fieldgroup.
 547          foreach (fieldgroup_groups($node->type) as $group) {
 548            fieldgroup_build_content($group, $node, $teaser, $page);
 549          }
 550        }
 551        break;
 552    }
 553  }
 554  
 555  /**
 556   * Build the node content element needed to render a fieldgroup.
 557   *
 558   * @param $group
 559   *   The field group definition.
 560   * @param $node
 561   *   The node containing the field group to display. Can be a 'pseudo-node',
 562   *   containing at least 'type', 'nid', 'vid', and the content for fields
 563   *   required for the group.
 564   * @param $teaser
 565   * @param $page
 566   *   Similar to hook_nodeapi('view').
 567   *
 568   * @see fieldgroup_nodeapi()
 569   * @see fieldgroup_view_group()
 570   */
 571  function fieldgroup_build_content($group, &$node, $teaser, $page) {
 572    // NODE_BUILD_NORMAL is 0, and ('whatever' == 0) is TRUE, so we need a ===.
 573    if ($node->build_mode === NODE_BUILD_NORMAL || $node->build_mode == NODE_BUILD_PREVIEW) {
 574      $context = $teaser ? 'teaser' : 'full';
 575    }
 576    else {
 577      $context = $node->build_mode;
 578    }
 579  
 580    $group_name = $group['group_name'];
 581  
 582    // Do not include group labels when indexing content.
 583    if ($context == NODE_BUILD_SEARCH_INDEX) {
 584      $group['settings']['display']['label'] = 'hidden';
 585    }
 586    $label = $group['settings']['display']['label'] == 'above';
 587    $element = array(
 588      '#title' => $label ? check_plain(t($group['label'])) : '',
 589      '#description' => $label ? content_filter_xss(t($group['settings']['display']['description'])) : '',
 590    );
 591    $format = isset($group['settings']['display'][$context]['format']) ? $group['settings']['display'][$context]['format'] : 'fieldset';
 592  
 593    switch ($format) {
 594      case 'simple':
 595        $element['#type'] = 'fieldgroup_simple';
 596        $element['#group_name'] = $group_name;
 597        $element['#node'] = $node;
 598        break;
 599      case 'hidden':
 600        $element['#access'] = FALSE;
 601        break;
 602      case 'fieldset_collapsed':
 603        $element['#collapsed'] = TRUE;
 604      case 'fieldset_collapsible':
 605        $element['#collapsible'] = TRUE;
 606      case 'fieldset':
 607        $element['#type'] = 'fieldgroup_fieldset';
 608        $element['#attributes'] = array('class' => 'fieldgroup '. strtr($group['group_name'], '_', '-'));
 609        break;
 610    }
 611    foreach ($group['fields'] as $field_name => $field) {
 612      if (isset($node->content[$field_name])) {
 613        $element[$field_name] = $node->content[$field_name];
 614      }
 615    }
 616  
 617    // Allow other modules to alter the group view.
 618    // Can't use module_invoke_all because we want
 619    // to be able to use a reference to $node and $element.
 620    foreach (module_implements('fieldgroup_view') as $module) {
 621      $function = $module .'_fieldgroup_view';
 622      $function($node, $element, $group, $context);
 623    }
 624  
 625    // Unset the original field values now that we've moved them.
 626    foreach ($group['fields'] as $field_name => $field) {
 627      if (isset($node->content[$field_name])) {
 628        unset($node->content[$field_name]);
 629      }
 630    }
 631  
 632    // The wrapper lets us get the themed output for the group
 633    // to populate the $GROUP_NAME_rendered variable for node templates,
 634    // and hide it from the $content variable if needed.
 635    // See fieldgroup_preprocess_node(), theme_fieldgroup_wrapper().
 636    $wrapper = array(
 637      'group' => $element,
 638      '#weight' => $group['weight'],
 639      '#post_render' => array('fieldgroup_wrapper_post_render'),
 640      '#group_name' => $group_name,
 641      '#type_name' => $node->type,
 642      '#context' => $context,
 643    );
 644  
 645    $node->content[$group_name] = $wrapper;
 646  }
 647  
 648  /**
 649   * Render a single field group, fully themed with label.
 650   *
 651   * To be used by third-party code (Panels, ...) that needs to output an
 652   * isolated field group. Do *not* use inside node templates, use the
 653   * $GROUP_NAME_rendered variables instead. You can also use the 'simple'
 654   * style format and override the template fieldgroup-simple.tpl.php.
 655   *
 656   * By default, the field group is displayed using the settings defined for the
 657   * 'full node' or 'teaser' contexts (depending on the value of the $teaser param).
 658   * Set $node->build_mode to a different value to use a different context.
 659   *
 660   * Different settings can be specified by adjusting $group['settings']['display'].
 661   *
 662   * @param $group
 663   *   The field group definition.
 664   * @param $node
 665   *   The node containing the field group to display. Can be a 'pseudo-node',
 666   *   containing at least 'type', 'nid', 'vid', and the field data required
 667   *   for the group.
 668   * @param $teaser
 669   * @param $page
 670   *   Similar to hook_nodeapi('view').
 671   * @return
 672   *   The themed output for the field group.
 673   *
 674   * @see content_view_field()
 675   */
 676  function fieldgroup_view_group($group, &$node, $teaser = FALSE, $page = FALSE) {
 677    $group_name = $group['group_name'];
 678    $field_types = _content_field_types();
 679  
 680    // Clone the node to prevent from altering the original.
 681    $node_copy = drupal_clone($node);
 682  
 683    // Use 'full'/'teaser' if not specified otherwise.
 684    $node_copy->build_mode = isset($node_copy->build_mode) ? $node_copy->build_mode : NODE_BUILD_NORMAL;
 685  
 686    // Build the content element for individual fields in the field group.
 687    if (!isset($node_copy->content)) {
 688      $node_copy->content = array();
 689    }
 690    foreach (array_keys($group['fields']) as $field_name) {
 691      $field = content_fields($field_name, $node_copy->type);
 692  
 693      if (isset($node_copy->{$field_name})) {
 694        $items = $node_copy->{$field_name};
 695  
 696        // One-field equivalent to _content_field_invoke('sanitize').
 697        $module = $field_types[$field['type']]['module'];
 698        $function = $module .'_field';
 699        if (function_exists($function)) {
 700          $function('sanitize', $node_copy, $field, $items, $teaser, $page);
 701          $node_copy->{$field_name} = $items;
 702        }
 703  
 704        $field_view = content_field('view', $node_copy, $field, $items, $teaser, $page);
 705        // content_field('view') adds a wrapper to handle variables and 'excluded'
 706        // fields for node templates. We bypass it and get the actual field.
 707        $node_copy->content[$field_name] = $field_view[$field_name];
 708      }
 709    }
 710  
 711    // Build the content element of the field group itself.
 712    fieldgroup_build_content($group, $node_copy, $teaser, $page);
 713  
 714    // fieldgroup_build_content() adds a wrapper to handle variables and 'excluded'
 715    // groups for node templates. We bypass it and render the actual field group.
 716    $output = drupal_render($node_copy->content[$group_name]['group']);
 717  
 718    return $output;
 719  }
 720  
 721  /**
 722   * Hide specified fields from the $content variable in node templates.
 723   */
 724  function fieldgroup_wrapper_post_render($content, $element) {
 725    $groups = fieldgroup_groups($element['#type_name']);
 726    $group = $groups[$element['#group_name']];
 727  
 728    // The display settings are not in quite the same place in the
 729    // group and the field, so create the value the theme will expect.
 730    $group['display_settings'] = $group['settings']['display'];
 731    if (theme('content_exclude', $content, $group, $element['#context'])) {
 732      return '';
 733    }
 734    return $content;
 735  }
 736  
 737  /*
 738   * Get the group name for a field.
 739   * If the field isn't in a group, FALSE will be returned.
 740   * @return The name of the group, or FALSE.
 741   */
 742  function fieldgroup_get_group($content_type, $field_name) {
 743    foreach (fieldgroup_groups($content_type) as $group_name => $group) {
 744      if (in_array($field_name, array_keys($group['fields']))) {
 745        return $group_name;
 746      }
 747    }
 748    return FALSE;
 749  }
 750  
 751  /**
 752   *  Implementation of hook_node_type()
 753   *  React to change in node types
 754   */
 755  function fieldgroup_node_type($op, $info) {
 756    if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
 757      // update the tables
 758      db_query("UPDATE {". fieldgroup_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type));
 759      db_query("UPDATE {". fieldgroup_fields_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type));
 760      cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 761    }
 762    elseif ($op == 'delete') {
 763      db_query("DELETE FROM {". fieldgroup_tablename() ."} WHERE type_name = '%s'", $info->type);
 764      db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s'", $info->type);
 765    }
 766  }
 767  
 768  function fieldgroup_types() {
 769    $types = array('standard' => t('Standard group'));
 770    // Allow other modules to add new group_types.
 771    $types = array_merge($types, module_invoke_all('fieldgroup_types'));
 772    return $types;
 773  }
 774  
 775  function fieldgroup_tablename($version = NULL) {
 776    if (is_null($version)) {
 777      $version = variable_get('fieldgroup_schema_version', 0);
 778    }
 779    return $version < 6000 ? 'node_group' : 'content_group';
 780  }
 781  
 782  function fieldgroup_fields_tablename($version = NULL) {
 783    if (is_null($version)) {
 784      $version = variable_get('fieldgroup_schema_version', 0);
 785    }
 786    return $version < 6000 ? 'node_group_fields' : 'content_group_fields';
 787  }
 788  
 789  /**
 790   * CRUD API for fieldgroup module.
 791   *
 792   * @todo
 793   * Make this into more of a real API for groups.
 794   */
 795  /*
 796   * Saves the given group for this content-type
 797   */
 798  function fieldgroup_save_group($type_name, $group) {
 799    $groups = fieldgroup_groups($type_name);
 800  
 801    // Allow other modules to intervene when the group is saved.
 802    foreach (module_implements('fieldgroup_save_group') as $module) {
 803      $function = $module .'_fieldgroup_save_group';
 804      $function($group);
 805    }
 806  
 807    if (!isset($groups[$group['group_name']])) {
 808      // Accept group name from programmed submissions if valid.
 809      db_query("INSERT INTO {". fieldgroup_tablename() ."} (group_type, type_name, group_name, label, settings, weight)".
 810        " VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $group['group_type'], $type_name, $group['group_name'], $group['label'], serialize($group['settings']), $group['weight']);
 811      cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 812      return SAVED_NEW;
 813    }
 814    else {
 815      db_query("UPDATE {". fieldgroup_tablename() ."} SET group_type = '%s', label = '%s', settings = '%s', weight = %d ".
 816               "WHERE type_name = '%s' AND group_name = '%s'",
 817               $group['group_type'], $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']);
 818      cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 819      return SAVED_UPDATED;
 820    }
 821  }
 822  
 823  function fieldgroup_update_fields($form_values) {
 824    $default = _fieldgroup_field_get_group($form_values['type_name'], $form_values['field_name']);
 825  
 826    if ($default != $form_values['group']) {
 827      if ($form_values['group'] && !$default) {
 828        db_query("INSERT INTO {". fieldgroup_fields_tablename() ."} (type_name, group_name, field_name) VALUES ('%s', '%s', '%s')", $form_values['type_name'], $form_values['group'], $form_values['field_name']);
 829      }
 830      elseif ($form_values['group']) {
 831        db_query("UPDATE {". fieldgroup_fields_tablename() ."} SET group_name = '%s' WHERE type_name = '%s' AND field_name = '%s'", $form_values['group'], $form_values['type_name'], $form_values['field_name']);
 832      }
 833      else {
 834        db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']);
 835      }
 836      cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 837    }
 838  }
 839  
 840  function fieldgroup_delete($content_type, $group_name) {
 841    db_query("DELETE FROM {". fieldgroup_tablename() ."} WHERE  type_name = '%s' AND group_name = '%s'", $content_type, $group_name);
 842    db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE  type_name = '%s' AND group_name = '%s'", $content_type, $group_name);
 843    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
 844  }
 845  
 846  /**
 847   * Format a fieldgroup using a 'fieldset'.
 848   *
 849   * Derived from core's theme_fieldset, with no output if the content is empty.
 850   */
 851  function theme_fieldgroup_fieldset($element) {
 852    if (empty($element['#children']) && empty($element['#value'])) {
 853      return '';
 854    }
 855  
 856    if ($element['#collapsible']) {
 857      drupal_add_js('misc/collapse.js');
 858  
 859      if (!isset($element['#attributes']['class'])) {
 860        $element['#attributes']['class'] = '';
 861      }
 862  
 863      $element['#attributes']['class'] .= ' collapsible';
 864      if ($element['#collapsed']) {
 865        $element['#attributes']['class'] .= ' collapsed';
 866      }
 867    }
 868    return '<fieldset'. drupal_attributes($element['#attributes']) .'>'. ($element['#title'] ? '<legend>'. $element['#title'] .'</legend>' : '') . (isset($element['#description']) && $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '') . (!empty($element['#children']) ? $element['#children'] : '') . (isset($element['#value']) ? $element['#value'] : '') ."</fieldset>\n";
 869  }
 870  
 871  
 872  /**
 873   * Process variables for fieldgroup.tpl.php.
 874   *
 875   * The $variables array contains the following arguments:
 876   * - $group_name
 877   * - $group_name_css
 878   * - $label
 879   * - $description
 880   * - $content
 881   *
 882   * @see fieldgroup-simple.tpl.php
 883   */
 884  function template_preprocess_fieldgroup_simple(&$vars) {
 885    $element = $vars['element'];
 886  
 887    $vars['group_name'] = $element['#group_name'];
 888    $vars['group_name_css'] = strtr($element['#group_name'], '_', '-');
 889    $vars['label'] = isset($element['#title']) ? $element['#title'] : '';;
 890    $vars['description'] = isset($element['#description']) ? $element['#description'] : '';;
 891    $vars['content'] = isset($element['#children']) ? $element['#children'] : '';
 892    $vars['template_files'] = array(
 893      'fieldgroup-simple-',
 894      'fieldgroup-simple-'. $element['#group_name'],
 895      'fieldgroup-simple-'. $element['#node']->type,
 896      'fieldgroup-simple-'. $element['#group_name'] .'-'. $element['#node']->type,
 897    );
 898  }
 899  
 900  /**
 901   * Theme preprocess function for node.
 902   *
 903   * Adds $GROUP_NAME_rendered variables,
 904   * containing the themed output for the whole group.
 905   */
 906  function fieldgroup_preprocess_node(&$vars) {
 907    $node = $vars['node'];
 908  
 909    foreach (fieldgroup_groups($node->type) as $group_name => $group) {
 910      // '#chilren' might not be set if the group is empty.
 911      $vars[$group_name .'_rendered'] = isset($node->content[$group_name]['#children']) ? $node->content[$group_name]['#children'] : '';
 912    }
 913  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7