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