[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/panels/includes/ -> common.inc (source)

   1  <?php
   2  // $Id: common.inc,v 1.10.2.12 2010/08/21 17:39:58 merlinofchaos Exp $
   3  
   4  
   5  /**
   6   * @file
   7   * Functions used by more than one panels client module.
   8   */
   9  
  10  /**
  11   * Class definition for the allowed layouts governing structure.
  12   *
  13   * @ingroup mainapi
  14   *
  15   * This class is designed to handle panels allowed layouts data from start to finish, and sees
  16   * action at two times:\n
  17   *    - When a client module wants to generate a form allowing an admin to create or edit a set
  18   *      of allowed layouts. In this case, either a new panels_allowed_layouts object is created
  19   *      or one is retrieved from storage and panels_allowed_layouts::set_allowed() is called to
  20   *      generate the allowed layouts form. \n
  21   *    - When a client module is calling panels_edit_layout(), a saved instantiation of this object
  22   *      can be called up and passed in to the fourth parameter, and only the allowed layouts saved
  23   *      in that object will be displayed on the form. \n
  24   * Because the panels API does not impose a data structure on the allowed_layouts data, client
  25   * modules can create as many of these objects as they want, and organize them around any concept:
  26   * node types, date published, author roles...anything.
  27   *
  28   * To call the settings form, instantiate this class - or, if your client module's needs are
  29   * heavy-duty, extend this class and instantiate your subclass - assign values to any relevant
  30   * desired members, and call panels_allowed_layouts::set_allowed(). See the documentation on
  31   * that method for a sample implementation.
  32   *
  33   * Note that when unserializing saved tokens of this class, you must
  34   * run panels_load_include('common') before unserializing in order to ensure
  35   * that the object is properly loaded.
  36   *
  37   * Client modules extending this class should implement a save() method and use it for
  38   * their custom data storage routine. You'll need to rewrite other class methods if
  39   * you choose to go another route.
  40   *
  41   * @see panels_edit_layout()
  42   * @see _panels_edit_layout()
  43   *
  44   */
  45  class panels_allowed_layouts {
  46  
  47    /**
  48     *  Specifies whether newly-added layouts (as in, new .inc files) should be automatically
  49     *  allowed (TRUE) or disallowed (FALSE) for $this. Defaults to TRUE, which is more
  50     *  permissive but less of an administrative hassle if/when you add new layouts. Note
  51     *  that this parameter will be derived from $allowed_layouts if a value is passed in.
  52     */
  53    var $allow_new = TRUE;
  54  
  55    /**
  56     *  Optional member. If provided, the Panels API will generate a drupal variable using
  57     *  variable_set($module_name . 'allowed_layouts', serialize($this)), thereby handling the
  58     *  storage of this object entirely within the Panels API. This object will be
  59     *  called and rebuilt by panels_edit_layout() if the same $module_name string is passed in
  60     *  for the $allowed_types parameter. \n
  61     *  This is primarily intended for convenience - client modules doing heavy-duty implementations
  62     *  of the Panels API will probably want to create their own storage method.
  63     * @see panels_edit_layout()
  64     */
  65    var $module_name = NULL;
  66  
  67    /**
  68     *  An associative array of all available layouts, keyed by layout name (as defined
  69     *  in the corresponding layout plugin definition), with value = 1 if the layout is
  70     *  allowed, and value = 0 if the layout is not allowed.
  71     *  Calling array_filter(panels_allowed_layouts::$allowed_layout_settings) will return an associative array
  72     *  containing only the allowed layouts, and wrapping that in array_keys() will
  73     *  return an indexed version of that array.
  74     */
  75    var $allowed_layout_settings = array();
  76  
  77    /**
  78     * Hack-imitation of D6's $form_state. Used by the panels_common_set_allowed_types()
  79     * form to indicate whether the returned value is in its 'render', 'failed-validate',
  80     * or 'submit' stage.
  81     */
  82    var $form_state;
  83  
  84    /**
  85     * Constructor function; loads the $allowed_layout_settings array with initial values according
  86     * to $start_allowed
  87     *
  88     * @param bool $start_allowed
  89     *  $start_allowed determines whether all available layouts will be marked
  90     *  as allowed or not allowed on the initial call to panels_allowed_layouts::set_allowed()
  91     *
  92     */
  93    function panels_allowed_layouts($start_allowed = TRUE) {
  94      // TODO would be nice if there was a way to just fetch the names easily
  95      foreach ($this->list_layouts() as $layout_name) {
  96        $this->allowed_layout_settings[$layout_name] = $start_allowed ? 1 : 0;
  97      }
  98    }
  99  
 100    /**
 101     * Manage panels_common_set_allowed_layouts(), the FAPI code for selecting allowed layouts.
 102     *
 103     * MAKE SURE to set panels_allowed_layouts::allow_new before calling this method. If you want the panels API
 104     * to handle saving these allowed layout settings, panels_allowed_layouts::module_name must also be set.
 105     *
 106     * Below is a sample implementation; refer to the rest of the class documentation to understand all the
 107     * specific pieces. Values that are intended to be replaced are wrapped with <>.
 108     *
 109     * \n @code
 110     *  function docdemo_allowed_layouts() {
 111     *    ctools_include('common', 'panels');
 112     *    if (!is_a($allowed_layouts = unserialize(variable_get('panels_common_allowed_layouts', serialize(''))), 'panels_allowed_layouts')) {
 113     *     $allowed_layouts = new panels_allowed_layouts();
 114     *      $allowed_layouts->allow_new = TRUE;
 115     *      $allowed_layouts->module_name = '<client_module_name>';
 116     *    }
 117     *    $result = $allowed_layouts->set_allowed('<Desired client module form title>');
 118     *    if (in_array($allowed_layouts->form_state, array('failed-validate', 'render'))) {
 119     *     return $result;
 120     *    }
 121     *    elseif ($allowed_layouts->form_state == 'submit') {
 122     *      drupal_goto('</path/to/desired/redirect>');
 123     *    }
 124     *  }
 125     * @endcode \n
 126     *
 127     * If $allowed_layouts->form_state == 'failed-validate' || 'render', then you'll need to return
 128     * $result as it contains the structured form HTML generated by drupal_render_form() and is ready
 129     * to be passed through index.php's call to theme('page', ...).
 130     *
 131     * However, if $allowed_layouts->form_state == 'submit', then the form has been submitted and we should
 132     * react. It's really up to your client module how you handle the rest; panels_allowed_layouts::save() (or
 133     * panels_allowed_layouts::api_save(), if that's the route you're going) will have already been called,
 134     * so if those methods handle your save routine, then all there is left to do is handle redirects, if you
 135     * want. The current implementation of the allowed layouts form currently never redirects, so it's up to
 136     * you to control where the user ends up next.
 137     *
 138     * @param string $title
 139     *  Used to set the title of the allowed layouts form. If no value is given, defaults to
 140     *  'Panels: Allowed Layouts'.
 141     *
 142     * @return mixed $result
 143     *  - On the first passthrough when the form is being rendered, $result is the form's structured
 144     *    HTML, ready to be pushed to the screen with a call to theme('page', ...).
 145     *  - A successful second passthrough indicates a successful submit, and
 146     *    $result === panels_allowed_layouts::allowed_layout_settings. Returning it is simply for convenience.
 147     */
 148    function set_allowed($title = 'Panels: Allowed Layouts') {
 149      $this->sync_with_available();
 150      $form_id = 'panels_common_set_allowed_layouts';
 151      // TODO switch to drupal_build_form(); need to pass by ref
 152      $form = drupal_retrieve_form($form_id, $this, $title);
 153  
 154      if ($result = drupal_process_form($form_id, $form)) {
 155        // successful submit
 156        $this->form_state = 'submit';
 157        return $result;
 158      }
 159      $this->form_state = isset($_POST['op']) ? 'failed-validate' : 'render';
 160      $result = drupal_render_form($form_id, $form);
 161      return $result;
 162    }
 163  
 164    /**
 165     * Checks for newly-added layouts and deleted layouts. If any are found, updates panels_allowed_layouts::allowed_layout_settings;
 166     * new additions are made according to panels_allowed_layouts::allow_new, while deletions are unset().
 167     *
 168     * Note that any changes made by this function are not saved in any permanent location.
 169     */
 170    function sync_with_available() {
 171      $layouts = $this->list_layouts();
 172      foreach (array_diff($layouts, array_keys($this->allowed_layout_settings)) as $new_layout) {
 173        $this->allowed_layout_settings[$new_layout] = $this->allow_new ? 1 : 0;
 174      }
 175      foreach (array_diff(array_keys($this->allowed_layout_settings), $layouts) as $deleted_layout) {
 176        unset($this->allowed_layout_settings[$deleted_layout]);
 177      }
 178    }
 179  
 180    /**
 181     * Use panels_allowed_layouts::module_name to generate a variable for variable_set(), in which
 182     * a serialized version of $this will be stored.
 183     *
 184     * Does nothing if panels_allowed_layouts::module_name is not set.
 185     *
 186     * IMPORTANT NOTE: if you use variable_get() in a custom client module save() method, you MUST
 187     * wrap $this in serialize(), then unserialize() what you get from variable_get(). Failure to
 188     * do so will result in an incomplete object. The following code will work:
 189     * @code
 190     *  $allowed_layouts = unserialize(variable_get('your_variable_name', serialize(''));
 191     * @endcode
 192     *
 193     * If you don't serialize the second parameter of variable_get() and the variable name you provide
 194     * can't be found, an E_STRICT warning will be generated for trying to unserialize an entity
 195     * that has not been serialized.
 196     *
 197     */
 198    function save() {
 199      if (!is_null($this->module_name)) {
 200        variable_set($this->module_name . "_allowed_layouts", serialize($this));
 201      }
 202    }
 203  
 204    /**
 205     * Snag a list of the current layouts for internal use.
 206     *
 207     * Data is not saved in a class member in order to ensure that it's
 208     * fresh.
 209     *
 210     * @return array $layouts
 211     *  An indexed array of the system names for all currently available layouts.
 212     */
 213    function list_layouts() {
 214      static $layouts = array();
 215      if (empty($layouts)) {
 216        ctools_include('plugins', 'panels');
 217        $layouts = array_keys(panels_get_layouts());
 218      }
 219      return $layouts;
 220    }
 221  }
 222  
 223  /**
 224   * A common settings page for Panels modules, because this code is relevant to
 225   * any modules that don't already have special requirements.
 226   */
 227  function panels_common_settings(&$form_state, $module_name = 'panels_common') {
 228    ctools_include('plugins', 'panels');
 229    ctools_include('content');
 230    $content_types = ctools_get_content_types();
 231    $skip = FALSE;
 232  
 233    $default_types = variable_get($module_name . '_default', NULL);
 234    if (!isset($default_types)) {
 235      $default_types = array('other' => TRUE);
 236      $skip = TRUE;
 237    }
 238  
 239    foreach ($content_types as $id => $info) {
 240      if (empty($info['single'])) {
 241        $default_options[$id] = t('New @s', array('@s' => $info['title']));
 242        if ($skip) {
 243          $default_types[$id] = TRUE;
 244        }
 245      }
 246    }
 247  
 248    $default_options['other'] = t('New content of other types');
 249    $form['panels_common_default'] = array(
 250      '#type' => 'checkboxes',
 251      '#title' => t('New content behavior'),
 252      '#description' => t('Select the default behavior of new content added to the system. If checked, new content will automatically be immediately available to be added to Panels pages. If not checked, new content will not be available until specifically allowed here.'),
 253      '#options' => $default_options,
 254      '#default_value' => array_keys(array_filter($default_types)),
 255    );
 256  
 257    $form_state['skip'] = $skip;
 258    if ($skip) {
 259      $form['markup'] = array('#value' => t('<p>Click Submit to be presented with a complete list of available content types set to the defaults you selected.</p>'));
 260    }
 261    else {
 262      // Rebuild the entire list, setting appropriately from defaults. Give
 263      // each type its own checkboxes set unless it's 'single' in which
 264      // case it can go into our fake other set.
 265      $available_content_types = ctools_content_get_all_types();
 266      $allowed_content_types = variable_get($module_name . '_allowed_types', array());
 267  
 268      foreach ($available_content_types as $id => $types) {
 269        foreach ($types as $type => $info) {
 270          $key = $id . '-' . $type;
 271          $checkboxes = empty($content_types[$id]['single']) ? $id : 'other';
 272          $options[$checkboxes][$key] = $info['title'];
 273          if (!isset($allowed_content_types[$key])) {
 274            $allowed[$checkboxes][$key] = isset($default_types[$id]) ? $default_types[$id] : $default_types['other'];
 275          }
 276          else {
 277            $allowed[$checkboxes][$key] = $allowed_content_types[$key];
 278          }
 279        }
 280      }
 281  
 282      $form['content_types'] = array(
 283        '#tree' => TRUE,
 284        '#prefix' => '<div class="clear-block">',
 285        '#suffix' => '</div>',
 286      );
 287      // cheat a bit
 288      $content_types['other'] = array('title' => t('Other'), 'weight' => 10);
 289      foreach ($content_types as $id => $info) {
 290        if (isset($allowed[$id])) {
 291          $form['content_types'][$id] = array(
 292            '#prefix' => '<div class="panels-page-type-container">',
 293            '#suffix' => '</div>',
 294            '#type' => 'checkboxes',
 295            '#title' => t('Allowed @s content', array('@s' => $info['title'])),
 296            '#options' => $options[$id],
 297            '#default_value' => array_keys(array_filter($allowed[$id])),
 298            '#checkall' => TRUE,
 299          );
 300        }
 301      }
 302    }
 303  
 304    panels_common_allowed_layouts_form($form, $form_state, $module_name);
 305  
 306    $form['module_name'] = array(
 307      '#type' => 'value',
 308      '#value' => $module_name,
 309    );
 310  
 311    $form['submit'] = array(
 312      '#type' => 'submit',
 313      '#value' => t('Save'),
 314    );
 315  
 316    ctools_add_css('panels_page', 'panels');
 317    return $form;
 318  }
 319  
 320  /**
 321   * Submit hook for panels_common_settings
 322   */
 323  function panels_common_settings_validate($form, &$form_state) {
 324    panels_common_allowed_layouts_form_validate($form, $form_state);
 325  }
 326  
 327  /**
 328   * Submit hook for panels_common_settings
 329   */
 330  function panels_common_settings_submit($form, &$form_state) {
 331    panels_common_allowed_layouts_form_submit($form, $form_state);
 332    $module_name = $form_state['values']['module_name'];
 333    variable_set($module_name . '_default', $form_state['values']['panels_common_default']);
 334    if (!$form_state['skip']) {
 335      // merge the broken apart array neatly back together
 336      variable_set($module_name . '_allowed_types', call_user_func_array('array_merge', $form_state['values']['content_types']));
 337    }
 338    drupal_set_message(t('Your changes have been saved.'));
 339  }
 340  
 341  /**
 342   * Based upon the settings, get the allowed types for this node.
 343   */
 344  function panels_common_get_allowed_types($module, $contexts = array(), $has_content = FALSE, $default_defaults = array(), $default_allowed_types = array()) {
 345    // Get a list of all types that are available
 346  
 347    $default_types = variable_get($module . '_default', $default_defaults);
 348    $allowed_types = variable_get($module . '_allowed_types', $default_allowed_types);
 349  
 350    // By default, if they haven't gone and done the initial setup here,
 351    // let all 'other' types (which will be all types) be available.
 352    if (!isset($default_types['other'])) {
 353      $default_types['other'] = TRUE;
 354    }
 355  
 356    ctools_include('content');
 357    $content_types = ctools_content_get_available_types($contexts, $has_content, $allowed_types, $default_types);
 358  
 359    return $content_types;
 360  }
 361  
 362  /**
 363   * The FAPI code for generating an 'allowed layouts' selection form.
 364   *
 365   * NOTE: Because the Panels API does not guarantee a particular method of storing the data on allowed layouts,
 366   * it is not_possible for the Panels API to implement any checks that determine whether reductions in
 367   * the set of allowed layouts conflict with pre-existing layout selections. $displays in that category
 368   * will continue to function with their current layout as normal until the user/owner/admin attempts
 369   * to change layouts on that display, at which point they will have to select from the new set of
 370   * allowed layouts. If this is not the desired behavior for your client module, it's up to you to
 371   * write a validation routine that determines what should be done with conflicting layouts.
 372   *
 373   * Remember that changing layouts where panes have already been created can result in data loss;
 374   * consult panels_change_layout() to see how the Panels API handles that process. Running
 375   * drupal_execute('panels_change_layout', ...) is one possible starting point.
 376   *
 377   * @ingroup forms
 378   *
 379   * @param array $allowed_layouts
 380   *  The set of allowed layouts that should be used as the default values
 381   *  for this form. If none is provided, then by default no layouts will be restricted.
 382   */
 383  function panels_common_allowed_layouts_form(&$form, &$form_state, $module_name) {
 384    // Fetch our allowed layouts from variables.
 385    $allowed_layouts = panels_common_get_allowed_layout_object($module_name);
 386  
 387    $layouts = panels_get_layouts();
 388    foreach ($layouts as $id => $layout) {
 389      $options[$id] = panels_print_layout_icon($id, $layout, check_plain($layout['title']));
 390    }
 391  
 392    $form_state['allowed_layouts'] = &$allowed_layouts;
 393  
 394    ctools_add_js('layout', 'panels');
 395    $form['layouts'] = array(
 396      '#type' => 'checkboxes',
 397      '#title' => t('Select allowed layouts'),
 398      '#options' => $options,
 399      '#description' => t('Check the boxes for all layouts you want to allow users choose from when picking a layout. You must allow at least one layout.'),
 400      '#default_value' => array_keys(array_filter($allowed_layouts->allowed_layout_settings)),
 401      '#prefix' => '<div class="clear-block panels-layouts-checkboxes">',
 402      '#suffix' => '</div>',
 403      '#checkall' => TRUE,
 404    );
 405  
 406    return $form;
 407  }
 408  
 409  function panels_common_allowed_layouts_form_validate($form, &$form_state) {
 410    $selected = array_filter($form_state['values']['layouts']);
 411    if (empty($selected)) {
 412      form_set_error('layouts', 'You must choose at least one layout to allow.');
 413    }
 414  }
 415  
 416  function panels_common_allowed_layouts_form_submit($form, &$form_state) {
 417    foreach ($form_state['values']['layouts'] as $layout => $setting) {
 418      $form_state['allowed_layouts']->allowed_layout_settings[$layout] = (bool) $setting;
 419    }
 420    $form_state['allowed_layouts']->save();
 421  }
 422  
 423  /**
 424   * Get the allowed layout object for the given module.
 425   */
 426  function panels_common_get_allowed_layout_object($module_name) {
 427    $allowed_layouts = unserialize(variable_get($module_name . "_allowed_layouts", serialize('')));
 428  
 429    // if no parameter was provided, or the variable_get failed
 430    if (!$allowed_layouts) {
 431      // still no dice. simply creates a dummy version where all layouts
 432      // are allowed.
 433      $allowed_layouts = new panels_allowed_layouts();
 434      $allowed_layouts->allow_new = TRUE;
 435      $allowed_layouts->module_name = $module_name;
 436    }
 437  
 438    // sanitize allowed layout listing; this is redundant if the
 439    // $allowed_layouts param was null, but the data is cached anyway
 440    $allowed_layouts->sync_with_available();
 441  
 442    return $allowed_layouts;
 443  }
 444  
 445  /**
 446   * Get the allowed layouts for the given module.
 447   */
 448  function panels_common_get_allowed_layouts($module_name) {
 449    $available_layouts = panels_get_layouts();
 450    if (empty($module_name)) {
 451      return $available_layouts;
 452    }
 453    else if (is_object($module_name)) {
 454      $allowed_layouts = $module_name;
 455    }
 456    else {
 457      $allowed_layouts = panels_common_get_allowed_layout_object($module_name);
 458    }
 459  
 460    $allowed = array_filter($allowed_layouts->allowed_layout_settings);
 461    $order = array();
 462    foreach ($available_layouts as $name => $plugin) {
 463      if (!empty($allowed[$name])) {
 464        $order[$name] = $plugin['category'] . ':' . $plugin['title'];
 465      }
 466    }
 467  
 468    // Sort
 469    $layouts = array();
 470  
 471    asort($order);
 472    foreach ($order as $name => $junk) {
 473      $layouts[$name] = $available_layouts[$name];
 474    }
 475  
 476    return $layouts;
 477  }
 478  
 479  /**
 480   * Create a visible list of content in a display.
 481   * Note that the contexts must be pre-loaded.
 482   */
 483  function theme_panels_common_content_list($display) {
 484    $layout = panels_get_layout($display->layout);
 485    $content = '<dl class="content-list">';
 486    foreach (panels_get_regions($layout, $display) as $panel_id => $title) {
 487      $content .= "<dt>$title</dt><dd>";
 488      if (!empty($display->panels[$panel_id])) {
 489        $content .= '<ol>';
 490        foreach ($display->panels[$panel_id] as $pid) {
 491          $content .= '<li>' . panels_get_pane_title($display->content[$pid], $display->context) . '</li>';
 492        }
 493        $content .= '</ol>';
 494      }
 495      else {
 496        $content .= t('Empty');
 497      }
 498      $content .= '</dd>';
 499    }
 500    $content .= '</dl>';
 501    return $content;
 502  }
 503  
 504  /**
 505   * Print a selector of layouts, each linked to the next step.
 506   *
 507   * Most operations use radio buttons for selecting layouts, but some will
 508   * give each layout as a link that goes to the next step. This function
 509   * makes it easy to simply provide a list of allowed layouts and the base
 510   * path.
 511   *
 512   * One limitation is that it will only append the layout name to the end, so
 513   * if the actual layout name is needed in the middle, that can't happen.
 514   *
 515   * @return
 516   *   The rendered output.
 517   */
 518  function panels_common_print_layout_links($layouts, $base_path, $link_options = array()) {
 519    $output = '';
 520  
 521    $categories = array();
 522    ctools_include('cleanstring');
 523    foreach ($layouts as $id => $layout) {
 524      $category = ctools_cleanstring($layout['category']);
 525  
 526      $categories[$category] = $layout['category'];
 527      $options[$category][$id] = panels_print_layout_link($id, $layout, $base_path . '/' . $id, $link_options);
 528    }
 529  
 530    $form = array();
 531    $form['categories'] = array(
 532      '#title' => t('Category'),
 533      '#type' => 'select',
 534      '#options' => $categories,
 535      '#name' => 'categories',
 536      '#id' => 'edit-categories',
 537      '#value' => '',
 538      '#parents' => array('categories'),
 539    );
 540  
 541    $output .= drupal_render($form);
 542  
 543    $output .= '<div class="panels-choose-layout panels-layouts-checkboxes clear-block">';
 544  
 545    // We're doing these dependencies completely manualy, which is unusual, but
 546    // the process code only supports doing them in a form.
 547    // @todo modify dependent.inc to make this easier.
 548  
 549    $dependencies = array();
 550    foreach ($options as $category => $links) {
 551      $dependencies['panels-layout-category-' . $category] = array(
 552        'values' => array('edit-categories' => array($category)),
 553        'num' => 1,
 554        'type' => 'hide',
 555      );
 556  
 557      $output .= '<div id="panels-layout-category-' . $category . '-wrapper">';
 558      $output .= '<div id="panels-layout-category-' . $category . '" class="form-checkboxes clear-block">';
 559      $output .= '<div class="panels-layouts-category">' . $categories[$category] . '</div>';
 560  
 561      foreach ($links as $key => $link) {
 562        $output .= $link;
 563      }
 564      $output .= '</div></div>';
 565    }
 566  
 567    $output .= '</div>';
 568  
 569    ctools_add_js('dependent');
 570    $js['CTools']['dependent'] = $dependencies;
 571    drupal_add_js($js, 'setting');
 572  
 573    return $output;
 574  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7