[ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * Functions for Plugin handling. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * Daniel HAHLER grants Francois PLANQUE the right to license 22 * Daniel HAHLER's contributions to this file and the b2evolution project 23 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 24 * }} 25 * 26 * @package evocore 27 * 28 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 29 * @author fplanque: Francois PLANQUE 30 * @author blueyed: Daniel HAHLER 31 * 32 * @version $Id: _plugin.funcs.php,v 1.2 2007/09/03 23:45:56 blueyed Exp $ 33 */ 34 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 35 36 37 /** 38 * Recursive helper function to display a field of the plugin's settings (by manipulating a Form). 39 * 40 * This gets used for PluginSettings ("Edit plugin") and PluginUserSettings ("Edit user settings"). 41 * 42 * @todo dh> Allow to move setting sets up and down (order). Control goes into /inc/CONTROL/settings/plugins.php. 43 * @todo NOTE: fp> I'm using this outside of Plugins; I'm not sure about proper factorization yet. 44 * This should probably be an extension of the Form class. Sth like "AutoForm" ;) 45 * 46 * @param string Settings path, e.g. 'locales[0]' or 'setting' 47 * @param array Meta data for this setting. 48 * @param Form (by reference) 49 * @param string Settings type ('Settings' or 'UserSettings' or 'Widget') 50 * @param Plugin|Widget 51 * @param mixed Target (User object for 'UserSettings') 52 * @param mixed Value to really use (used for recursion into array type settings) 53 */ 54 function autoform_display_field( $parname, $parmeta, & $Form, $set_type, $Obj, $set_target = NULL, $use_value = NULL ) 55 { 56 global $debug; 57 global $htsrv_url; 58 static $has_array_type; 59 60 if( ! empty($parmeta['no_edit']) ) 61 { // this setting is not editable 62 return; 63 } 64 65 $params = array(); 66 67 if( $use_value === NULL ) 68 { // outermost level 69 $has_array_type = false; // for adding a note about JS 70 $outer_most = true; 71 } 72 else 73 { 74 $outer_most = false; 75 } 76 77 // Passthrough some attributes to elements: 78 foreach( $parmeta as $k => $v ) 79 { 80 if( in_array( $k, array( 'id', 'onchange', 'onclick', 'onfocus', 'onkeyup', 'onkeydown', 'onreset', 'onselect', 'cols', 'rows', 'maxlength' ) ) ) 81 { 82 $params[$k] = $v; 83 } 84 } 85 if( ! empty($parmeta['multiple']) ) 86 { // "multiple" attribute for "select" inputs: 87 $params['multiple'] = 'multiple'; 88 } 89 90 if( isset($parmeta['note']) ) 91 { 92 $params['note'] = $parmeta['note']; 93 } 94 95 if( ! isset($parmeta['type']) || $parmeta['type'] == 'html_input' ) 96 { 97 $parmeta['type'] = 'text'; 98 } 99 elseif( $parmeta['type'] == 'html_textarea' ) 100 { 101 $parmeta['type'] = 'textarea'; 102 } 103 104 if( strpos($parmeta['type'], 'select_') === 0 ) 105 { // 'allow_none' setting for select_* types 106 if( isset($parmeta['allow_none']) ) 107 { 108 $params['allow_none'] = $parmeta['allow_none']; 109 } 110 } 111 112 $help_icon = NULL; 113 if( isset($parmeta['help']) ) 114 { 115 if( $parmeta['help'] === true ) 116 { // link to $parname-target: 117 $help_target = '#'.preg_replace( array('~\]?\[\d+\]\[~', '~\]$~'), array('_',''), $parname ); 118 } 119 else 120 { 121 $help_target = $parmeta['help']; 122 } 123 $help_icon = $Obj->get_help_link( $help_target ); 124 } 125 126 $set_label = isset($parmeta['label']) ? $parmeta['label'] : ''; 127 128 if( ! empty($parmeta['disabled']) ) 129 { 130 $params['disabled'] = 'disabled'; 131 } 132 133 134 // "Layout" settings: 135 if( isset($parmeta['layout']) ) 136 { 137 switch( $parmeta['layout'] ) 138 { 139 case 'begin_fieldset': 140 $fieldset_title = $set_label; 141 if( isset($help_icon) ) 142 { 143 $Form->begin_fieldset( $fieldset_title, array(), array($help_icon) ); 144 } 145 else 146 { 147 $Form->begin_fieldset( $fieldset_title ); 148 } 149 break; 150 151 case 'end_fieldset': 152 $Form->end_fieldset(); 153 break; 154 155 case 'separator': 156 echo '<hr />'; 157 break; 158 } 159 return; 160 } 161 162 if( ! empty($help_icon) ) 163 { // Append help icon to note: 164 if( empty($params['note']) ) 165 { 166 $params['note'] = $help_icon; 167 } 168 else 169 { 170 $params['note'] .= ' '.$help_icon; 171 } 172 } 173 174 if( isset($use_value) ) 175 { 176 $set_value = $use_value; 177 } 178 else 179 { 180 switch( $set_type ) 181 { 182 case 'Widget': 183 $set_value = $Obj->get_param( $parname ); 184 $error_value = NULL; 185 break; 186 187 case 'UserSettings': 188 // NOTE: this assumes we come here only on recursion or with $use_value set..! 189 $set_value = $Obj->UserSettings->get( $parname, $set_target->ID ); 190 $error_value = $Obj->PluginUserSettingsValidateSet( $tmp_params = array( 191 'name' => $parname, 192 'value' => & $set_value, 193 'meta' => $parmeta, 194 'User' => $set_target, 195 'action' => 'display' ) ); 196 break; 197 198 case 'Settings': 199 // NOTE: this assumes we come here only on recursion or with $use_value set..! 200 $set_value = $Obj->Settings->get( $parname ); 201 $error_value = $Obj->PluginSettingsValidateSet( $tmp_params = array( 202 'name' => $parname, 203 'value' => & $set_value, 204 'meta' => $parmeta, 205 'action' => 'display' ) ); 206 break; 207 208 default: 209 debug_die( "unhandled set_type $set_type" ); 210 break; 211 } 212 213 if( $error_value ) 214 { // add error 215 param_error( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, NULL, $error_value ); // only add the error to the field 216 } 217 } 218 219 // Display input element: 220 $input_name = 'edit_plugin_'.$Obj->ID.'_set_'.$parname; 221 if( substr($parmeta['type'], 0, 6) == 'select' && ! empty($parmeta['multiple']) ) 222 { // a "multiple" select: 223 $input_name .= '[]'; 224 } 225 switch( $parmeta['type'] ) 226 { 227 case 'checkbox': 228 $Form->checkbox_input( $input_name, $set_value, $set_label, $params ); 229 break; 230 231 case 'textarea': 232 $textarea_rows = isset($parmeta['rows']) ? $parmeta['rows'] : 3; 233 $Form->textarea_input( $input_name, $set_value, $textarea_rows, $set_label, $params ); 234 break; 235 236 case 'select': 237 $params['force_keys_as_values'] = true; // so that numeric keys get used as values! autoform_validate_param_value() checks for the keys only. 238 $Form->select_input_array( $input_name, $set_value, $parmeta['options'], $set_label, NULL, $params ); 239 break; 240 241 case 'select_blog': 242 $BlogCache = & get_Cache( 'BlogCache' ); 243 $Form->select_input_object( $input_name, $set_value, $BlogCache, $set_label, $params ); 244 break; 245 246 case 'select_group': 247 $GroupCache = & get_Cache( 'GroupCache' ); 248 $Form->select_input_object( $input_name, $set_value, $GroupCache, $set_label, $params ); 249 break; 250 251 case 'select_user': 252 $UserCache = & get_Cache( 'UserCache' ); 253 $UserCache->load_all(); 254 if( ! isset($params['loop_object_method']) ) 255 { 256 $params['loop_object_method'] = 'get_preferred_name'; 257 } 258 $Form->select_input_object( $input_name, $set_value, $UserCache, $set_label, $params ); 259 break; 260 261 case 'array': 262 $has_array_type = true; 263 264 if( substr_count( $parname, '[' ) % 2 ) 265 { // this refers to a specific array type set (with index pos at the end), e.g. when adding a field through AJAX: 266 $pos_last_bracket = strrpos($parname, '['); 267 $k_nb = substr( $parname, $pos_last_bracket+1, -1 ); 268 $disp_arrays = array( '' => $set_value ); // empty key.. 269 $parname = substr($parname, 0, $pos_last_bracket); 270 } 271 else 272 { // display all values hold in this set: 273 $disp_whole_set = true; 274 $disp_arrays = $set_value; 275 $fieldset_title = $set_label; 276 if( $debug ) 277 { 278 $fieldset_title .= ' [debug: '.$parname.']'; 279 } 280 $Form->begin_fieldset( $fieldset_title ); 281 282 if( ! empty($params['note']) ) 283 { 284 echo '<p class="notes">'.$params['note'].'</p>'; 285 } 286 $k_nb = 0; 287 } 288 289 290 $user_ID = $set_type == 'UserSettings' ? $set_target->ID : ''; 291 if( is_array( $set_value ) && ! empty($set_value) ) 292 { // Display value of the setting. It may be empty, if there's no set yet. 293 foreach( $disp_arrays as $k => $v ) 294 { 295 $fieldset_icons = array(); 296 if( ! isset($parmeta['min_count']) || count($set_value) > $parmeta['min_count'] ) 297 { // provide icon to remove this set 298 $fieldset_icons[] = action_icon( 299 T_('Delete set!'), 300 'delete', 301 regenerate_url( 'action', array('action=del_settings_set&set_path='.$parname.'['.$k.']'.( $set_type == 'UserSettings' ? '&user_ID='.$user_ID : '' ), 'plugin_ID='.$Obj->ID) ), 302 '', 303 5, 0, /* icon/text prio */ 304 // attach onclick event to remove the whole fieldset (AJAX): 305 array( 306 'onclick' => " 307 var oThis = this; 308 \$.get('{$htsrv_url}async.php', { 309 action: 'del_plugin_sett_set', 310 plugin_ID: '{$Obj->ID}', 311 user_ID: '$user_ID', 312 set_type: '$set_type', 313 set_path: '{$parname}[$k]' 314 }, 315 function(r, status) { 316 if( r == 'OK' ) 317 { 318 \$(oThis).parents('fieldset:first').remove(); 319 } 320 } ); 321 return false;", 322 ) 323 ); 324 } 325 $Form->begin_fieldset( '#'.$k_nb, array('class'=>'bordered'), $fieldset_icons ); 326 327 if( isset($parmeta['key']) ) 328 { // KEY FOR THIS ENTRY: 329 if( ! strlen($k) && isset($parmeta['key']['defaultvalue']) ) 330 { // key is not given/set and we have a default: 331 $l_value = $parmeta['key']['defaultvalue']; 332 } 333 else 334 { 335 $l_value = $k; 336 } 337 // RECURSE: 338 autoform_display_field( $parname.'['.$k_nb.'][__key__]', $parmeta['key'], $Form, $set_type, $Obj, $set_target, $l_value ); 339 } 340 341 foreach( $parmeta['entries'] as $l_set_name => $l_set_entry ) 342 { 343 $l_value = isset($set_value[$k][$l_set_name]) ? $set_value[$k][$l_set_name] : NULL; 344 // RECURSE: 345 autoform_display_field( $parname.'['.$k_nb.']['.$l_set_name.']', $l_set_entry, $Form, $set_type, $Obj, $set_target, $l_value ); 346 } 347 $Form->end_fieldset(); 348 $k_nb++; 349 } 350 } 351 352 // TODO: fix this for AJAX callbacks, when removing and re-adding items (dh): 353 if( ! isset( $parmeta['max_number'] ) || $parmeta['max_number'] > ($k_nb) ) 354 { // no max_number defined or not reached: display link to add a new set 355 $set_path = $parname.'['.$k_nb.']'; 356 357 echo '<div>'; 358 echo action_icon( 359 sprintf( T_('Add a new set of «%s»'), $set_label), 360 'new', 361 regenerate_url( 'action', array('action=add_settings_set', 'set_path='.$set_path.( $set_type == 'UserSettings' ? '&user_ID='.get_param('user_ID') : '' ), 'plugin_ID='.$Obj->ID) ), 362 T_('New set'), 363 5, 1, /* icon/text prio */ 364 array('onclick'=> " 365 var oThis = this; 366 \$.get('{$htsrv_url}async.php', { 367 action: 'add_plugin_sett_set', 368 plugin_ID: '{$Obj->ID}', 369 set_type: '$set_type', 370 set_path: '$set_path' 371 }, 372 function(r, status) { 373 \$(oThis).parent('div').html(r); 374 } 375 ); 376 return false;") 377 ); 378 echo '</div>'; 379 } 380 381 if( ! empty($disp_whole_set) ) 382 { // close the surrounding fieldset: 383 $Form->end_fieldset(); 384 } 385 386 break; 387 388 case 'password': 389 $params['type'] = 'password'; // same as text input, but type=password 390 391 case 'float': 392 case 'integer': 393 case 'text': 394 // Default: "text input" 395 if( isset($parmeta['size']) ) 396 { 397 $size = (int)$parmeta['size']; 398 } 399 else 400 { // Default size: 401 $size = 15; 402 } 403 if( isset($parmeta['maxlength']) ) 404 { 405 $params['maxlength'] = (int)$parmeta['maxlength']; 406 } 407 else 408 { // do not use size as maxlength, if not given! 409 $params['maxlength'] = ''; 410 } 411 412 $Form->text_input( $input_name, $set_value, $size, $set_label, '', $params ); // TEMP: Note already in params 413 break; 414 415 default: 416 debug_die( 'Unsupported type ['.$parmeta['type'].'] from GetDefaultSettings()!' ); 417 } 418 419 if( $outer_most && $has_array_type ) 420 { // Note for Non-Javascript users: 421 echo '<script type="text/javascript"></script><noscript>'; 422 echo '<p class="note">'.T_('Note: before adding a new set you have to save any changes.').'</p>'; 423 echo '</noscript>'; 424 } 425 } 426 427 428 /** 429 * Helper method for "add_settings_set" and "delete_settings_set" action. 430 * 431 * Walks the given settings path and either inits the target entry or unsets it ($init_value=NULL). 432 * 433 * @param Plugin 434 * @param string Settings type ("Settings" or "UserSettings") 435 * @param string The settings path, e.g. 'setting[0]foo[1]'. (Is used as array internally for recursion.) 436 * @param mixed The initial value of the setting, typically array() - NULL to unset it (action "delete_settings_set" uses it) 437 * @return array|false 438 */ 439 function _set_setting_by_path( & $Plugin, $set_type, $path, $init_value = array() ) 440 { 441 $r = get_plugin_settings_node_by_path( $Plugin, $set_type, $path, true ); 442 if( $r === false ) 443 { 444 return false; 445 } 446 447 // Make return value handier. Note: list() would copy and destroy the references (setting and set_node)! 448 $set_name = & $r['set_name']; 449 $set_node = & $r['set_node']; 450 $set_meta = & $r['set_meta']; 451 $set_parent = & $r['set_parent']; 452 $set_key = & $r['set_key']; 453 $setting = & $r['setting']; 454 #pre_dump( $r ); 455 456 #if( isset($set_node) && $init_value !== NULL ) 457 #{ // Setting already exists (and we do not want to delete), e.g. page reload! 458 # return false; 459 # /* 460 # while( isset($l_setting[ $path[0] ]) ) 461 # { // bump the index until not set 462 # $path[0]++; 463 # } 464 # */ 465 #} 466 #else 467 if( is_null($init_value) ) 468 { // NULL is meant to unset it 469 unset($set_parent[$set_key]); 470 } 471 else 472 { // Init entries: 473 // destroys reference: $set_node = $init_value; 474 475 // Copy meta entries: 476 foreach( $set_meta['entries'] as $k => $v ) 477 { 478 if( isset( $v['defaultvalue'] ) ) 479 { // set to defaultvalue 480 $set_node[$k] = $v['defaultvalue']; 481 } 482 else 483 { 484 if( isset($v['type']) && $v['type'] == 'array' ) 485 { 486 $set_node[$k] = array(); 487 } 488 else 489 { 490 $set_node[$k] = ''; 491 } 492 } 493 } 494 } 495 496 // Set it into $Plugin->Settings or $Plugin->UserSettings: 497 $Plugin->$set_type->set( $set_name, $setting ); 498 499 return $setting; 500 } 501 502 503 /** 504 * Get a node from settings by path (e.g. "locales[0][questions]") 505 * 506 * @param Plugin 507 * @param string Settings type ("Settings" or "UserSettings") 508 * @param string The settings path, e.g. 'setting[0]foo[1]' or even 'setting[]'. (Is used as array internally for recursion.) 509 * @return array Array( 510 * - 'set_name': setting name (string); key of the first level 511 * - 'set_node': selected setting node, may be NULL (by reference) 512 * - 'set_meta': meta info (from GetDefault[User]Settings()) for selected node (array) 513 * - 'set_parent': parent node (by reference) 514 * - 'set_key': key in parent node (by reference) 515 * - 'setting': whole settings (array) 516 */ 517 function get_plugin_settings_node_by_path( & $Plugin, $set_type, $path, $create = false ) 518 { 519 // Init: 520 if( ! preg_match( '~^\w+(\[\w+\])+$~', $path ) ) 521 { 522 debug_die( 'Invalid path param!' ); 523 } 524 525 $path = preg_split( '~(\[|\]\[?)~', $path, -1 ); // split by "[" and "][", so we get an array with setting name and index alternating 526 $foo = array_pop($path); // remove last one 527 if( ! empty($foo) ) 528 debug_die('Assertion failed!'); 529 530 $set_name = $path[0]; 531 532 $setting = $Plugin->$set_type->get($set_name); // $Plugin->Settings or $Plugin->UserSettings 533 534 // meta info for this setting: 535 $method = 'GetDefault'.$set_type; // GetDefaultSettings or GetDefaultUserSettings 536 $defaults = $Plugin->$method( $tmp_params = array('for_editing'=>true) ); 537 if( ! isset($defaults[ $set_name ]) ) 538 { 539 //debug_die( 'Invalid setting ('.$set_name.') - no meta data!' ); 540 return false; 541 } 542 543 $found_node = & $setting; 544 $defaults_node = & $defaults; 545 $set_meta = $defaults[$set_name]; 546 $set_parent = NULL; 547 $set_key = NULL; 548 549 $count = 0; 550 while( count($path) ) 551 { 552 $count++; 553 554 $loop_name = array_shift($path); 555 556 if( $count > 1 ) 557 { 558 $set_parent = & $found_node[$loop_name]; 559 $set_key = NULL; 560 $defaults_node = & $defaults_node['entries'][$loop_name]; 561 $found_node = & $found_node[$loop_name]; 562 } 563 else 564 { 565 $defaults_node = & $defaults_node[$loop_name]; 566 $set_parent = & $setting; 567 } 568 569 if( count($path) ) 570 { // has an index => array 571 $loop_index = array_shift($path); 572 573 #$set_parent = & $set_parent[$loop_name]; 574 $set_key = $loop_index; 575 576 if( $set_key === '' ) 577 { // []-syntax: append entry 578 if( $create && ! count($path) ) 579 { // only create, if at the end 580 $found_node[] = array(); 581 } 582 $found_node = & $found_node[ array_pop(array_keys($found_node)) ]; 583 } 584 else 585 { // specific key: 586 if( ! isset($found_node[$loop_index]) ) 587 { 588 $found_node[$loop_index] = array(); 589 } 590 $found_node = & $found_node[$loop_index]; 591 } 592 } 593 } 594 595 #echo '<h1>RETURN</h1>'; pre_dump( $set_parent, $set_key ); 596 return array( 597 'set_name' => $set_name, 598 'set_node' => & $found_node, 599 'set_meta' => $defaults_node, 600 'set_parent' => & $set_parent, 601 'set_key' => & $set_key, 602 'setting' => & $setting ); 603 } 604 605 606 /** 607 * Set Plugin settings from params. 608 * 609 * fp> WARNING: also used outside of plugins. Work in progress. 610 * 611 * This handled plugin specific params when saving a user profile (PluginUserSettings) or plugin settings (PluginSettings). 612 * 613 * @param string Settings path, e.g. 'locales[0]' or 'setting' 614 * @param array Meta data for this setting. 615 * @param Plugin|Widget 616 * @param string Type of Settings (either 'Settings' or 'UserSettings'). 617 * @param mixed Target (User object for 'UserSettings') 618 */ 619 function autoform_set_param_from_request( $parname, $parmeta, & $Obj, $set_type, $set_target = NULL ) 620 { 621 if( isset($parmeta['layout']) ) 622 { // a layout "setting" 623 return; 624 } 625 626 if( ! empty($parmeta['disabled']) || ! empty($parmeta['no_edit']) ) 627 { // the setting is disabled 628 return; 629 } 630 631 $l_param_type = 'string'; 632 $l_param_default = ''; 633 if( isset($parmeta['type']) ) 634 { 635 if( substr($parmeta['type'], 0, 6) == 'select' && ! empty($parmeta['multiple']) ) 636 { // a "multiple" select: 637 $l_param_type = 'array'; 638 } 639 switch( $parmeta['type'] ) 640 { 641 case 'array': 642 // this settings has a type 643 $l_param_type = $parmeta['type']; 644 break; 645 646 case 'checkbox': 647 $l_param_type = 'integer'; 648 $l_param_default = 0; 649 break; 650 651 case 'html_input': 652 case 'html_textarea': 653 $l_param_type = 'html'; 654 break; 655 656 default: 657 } 658 } 659 660 // Get the value: 661 $l_value = param( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, $l_param_type, $l_param_default ); 662 // pre_dump( $parname, $l_value ); 663 664 if( isset($parmeta['type']) && $parmeta['type'] == 'array' ) 665 { // make keys (__key__) in arrays unique and remove them 666 handle_array_keys_in_plugin_settings($l_value); 667 } 668 669 if( ! autoform_validate_param_value('edit_plugin_'.$Obj->ID.'_set_'.$parname, $l_value, $parmeta) ) 670 { 671 return; 672 } 673 674 // Validate form values: 675 switch( $set_type ) 676 { 677 case 'Widget': 678 $error_value = NULL; 679 $Obj->set( $parname, $l_value ); 680 break; 681 682 case 'UserSettings': 683 // Plugin User settings: 684 $error_value = $Obj->PluginUserSettingsValidateSet( $dummy = array( 685 'name' => $parname, 686 'value' => & $l_value, 687 'meta' => $parmeta, 688 'User' => $set_target, 689 'action' => 'set' ) ); 690 // Update the param value, because a plugin might have changed it (through reference): 691 $GLOBALS['edit_plugin_'.$Obj->ID.'_set_'.$parname] = $l_value; 692 693 if( empty( $error_value ) ) 694 { 695 $Obj->UserSettings->set( $parname, $l_value, $set_target->ID ); 696 } 697 break; 698 699 case 'Settings': 700 // Plugin global settings: 701 $error_value = $Obj->PluginSettingsValidateSet( $dummy = array( 702 'name' => $parname, 703 'value' => & $l_value, 704 'meta' => $parmeta, 705 'action' => 'set' ) ); 706 // Update the param value, because a plugin might have changed it (through reference): 707 $GLOBALS['edit_plugin_'.$Obj->ID.'_set_'.$parname] = $l_value; 708 709 if( empty( $error_value ) ) 710 { 711 $Obj->Settings->set( $parname, $l_value ); 712 } 713 break; 714 715 default: 716 debug_die( "unhandled set_type $set_type" ); 717 break; 718 } 719 720 if( $error_value ) 721 { // A validation error has occured, record error message: 722 param_error( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, $error_value ); 723 } 724 } 725 726 727 /** 728 * Validates settings according to their meta info recursively. 729 * 730 * @todo Init "checkbox" values in "array" type settings (they do not get send) (dh) 731 * @param string Param name 732 * @param array Meta info 733 * @return boolean 734 */ 735 function autoform_validate_param_value( $param_name, $value, $meta ) 736 { 737 global $Messages; 738 739 if( is_array($value) && isset($meta['entries']) ) 740 { 741 $r = true; 742 if(isset($meta['key'])) 743 { // validate keys: 744 foreach( array_keys($value) as $k ) 745 { 746 if( ! autoform_validate_param_value($param_name.'['.$k.'][__key__]', $k, $meta['key']) ) 747 { 748 $r = false; 749 } 750 } 751 } 752 753 // Check max_count/min_count 754 // dh> TODO: find a way to link it to the form's fieldset (and add an "error" class to it) 755 if( isset($meta['max_count']) && count($value) > $meta['max_count'] ) 756 { 757 $r = false; 758 $label = isset($meta['label']) ? $meta['label'] : $param_name; 759 $Messages->add( sprintf( T_('Too many entries in the "%s" set. It must have %d at most.'), $label, $meta['max_count'] ), 'error' ); 760 } 761 elseif( isset($meta['min_count']) && count($value) < $meta['min_count'] ) 762 { 763 $r = false; 764 $label = isset($meta['label']) ? $meta['label'] : $param_name; 765 $Messages->add( sprintf( T_('Too few entries in the "%s" set. It must have %d at least.'), $label, $meta['min_count'] ), 'error' ); 766 } 767 768 foreach( $meta['entries'] as $mk => $mv ) 769 { 770 foreach( $value as $vk => $vv ) 771 { 772 if( ! isset($vv[$mk]) ) 773 continue; 774 775 if( ! autoform_validate_param_value($param_name.'['.$vk.']['.$mk.']', $vv[$mk], $mv) ) 776 { 777 $r = false; 778 } 779 } 780 } 781 return $r; 782 } 783 784 785 if( isset($meta['type']) ) 786 { 787 switch( $meta['type'] ) 788 { 789 case 'integer': 790 if( ! preg_match( '~^[-+]?\d+$~', $value ) ) 791 { 792 param_error( $param_name, sprintf( T_('The value for «%s» must be numeric.'), $meta['label'] ), T_('The value must be numeric.') ); 793 return false; 794 } 795 break; 796 797 case 'float': 798 if( ! preg_match( '~^[-+]?\d+(\.\d+)?$~', $value ) ) 799 { 800 param_error( $param_name, sprintf( T_('The value for «%s» must be numeric.'), $meta['label'] ), T_('The value must be numeric.') ); 801 return false; 802 } 803 break; 804 805 case 'select': 806 $check_options = $value; 807 if( ! is_array($check_options) ) 808 { // no "multiple" select: 809 $check_options = array($check_options); 810 } 811 812 foreach($check_options as $v) 813 { 814 if( ! in_array( $v, array_keys($meta['options']) ) ) 815 { 816 param_error( $param_name, sprintf( T_('Invalid option «%s».'), $v ) ); 817 return false; 818 } 819 } 820 break; 821 822 case 'select_blog': 823 case 'select_group': 824 case 'select_user': 825 if( is_array($value) && empty($value) // empty "multiple" select 826 || ( ! is_array($value) && ! strlen($value) ) ) 827 { 828 if( empty($meta['allow_none']) ) 829 { // empty is not ok 830 param_error( $param_name, sprintf( T_('Invalid option «%s».'), $value ) ); 831 return false; 832 } 833 } 834 else 835 { // Try retrieving the value from the corresponding Cache: 836 switch( $meta['type'] ) 837 { 838 case 'select_blog': 839 $Cache = & get_Cache( 'BlogCache' ); 840 break; 841 842 case 'select_group': 843 $Cache = & get_Cache( 'GroupCache' ); 844 break; 845 846 case 'select_user': 847 $Cache = & get_Cache( 'UserCache' ); 848 break; 849 } 850 851 $check_options = $value; 852 if( ! is_array($check_options) ) 853 { // no "multiple" select: 854 $check_options = array($check_options); 855 } 856 857 foreach($check_options as $v) 858 { 859 if( empty($v) && ! empty($meta['allow_none']) ) 860 { // empty is ok: 861 continue; 862 } 863 if( ! $Cache->get_by_ID($v, false, false) ) 864 { 865 param_error( $param_name, sprintf( T_('Invalid option «%s».'), $v ) ); 866 return false; 867 } 868 } 869 } 870 break; 871 } 872 } 873 874 // Check maxlength: 875 if( isset($meta['maxlength']) ) 876 { 877 if( strlen($value) > $meta['maxlength'] ) 878 { 879 param_error( $param_name, sprintf( T_('The value is too long.'), $value ) ); 880 } 881 } 882 883 // Check valid pattern: 884 if( isset($meta['valid_pattern']) ) 885 { 886 $param_pattern = is_array($meta['valid_pattern']) ? $meta['valid_pattern']['pattern'] : $meta['valid_pattern']; 887 if( ! preg_match( $param_pattern, $value ) ) 888 { 889 $param_error = is_array($meta['valid_pattern']) ? $meta['valid_pattern']['error'] : sprintf(T_('The value is invalid. It must match the regular expression «%s».'), $param_pattern); 890 param_error( $param_name, $param_error ); 891 return false; 892 } 893 } 894 895 // Check valid range: 896 if( isset($meta['valid_range']) ) 897 { 898 // Transform numeric indexes into associative keys: 899 if( ! isset($meta['valid_range']['min'], $meta['valid_range']['max']) 900 && isset($meta['valid_range'][0], $meta['valid_range'][1]) ) 901 { 902 $meta['valid_range']['min'] = $meta['valid_range'][0]; 903 $meta['valid_range']['max'] = $meta['valid_range'][1]; 904 } 905 if( isset($meta['valid_range'][2]) && ! isset($meta['valid_range']['error']) ) 906 { 907 $meta['valid_range']['error'] = $meta['valid_range'][2]; 908 } 909 910 if( (isset($meta['valid_range']['min']) && $value < $meta['valid_range']['min']) 911 || (isset($meta['valid_range']['max']) && $value > $meta['valid_range']['max']) ) 912 { 913 if( isset($meta['valid_range']['error']) ) 914 { 915 $param_error = $meta['valid_range']['error']; 916 } 917 else 918 { 919 if( isset($meta['valid_range']['min']) && isset($meta['valid_range']['max']) ) 920 { 921 $param_error = sprintf(T_('The value is invalid. It must be in the range from %s to %s.'), $meta['valid_range']['min'], $meta['valid_range']['max']); 922 } 923 elseif( isset($meta['valid_range']['max']) ) 924 { 925 $param_error = sprintf(T_('The value is invalid. It must be smaller than %s.'), $meta['valid_range']['max']); 926 } 927 else 928 { 929 $param_error = sprintf(T_('The value is invalid. It must be greater than %s.'), $meta['valid_range']['min']); 930 } 931 } 932 933 param_error( $param_name, $param_error ); 934 return false; 935 } 936 } 937 938 return true; 939 } 940 941 942 /** 943 * This handles the special "__key__" index in all array type values 944 * in the given array. It makes sure, that "__key__" is unique and 945 * replaces the original key of the value with it. 946 * @param array (by reference) 947 */ 948 function handle_array_keys_in_plugin_settings( & $a ) 949 { 950 if( ! is_array($a) ) 951 { 952 return; 953 } 954 955 $new_arr = array(); // use a new array to maintain order, also for "numeric" keys 956 957 foreach( array_keys($a) as $k ) 958 { 959 $v = & $a[$k]; 960 961 if( is_array($v) && isset($v['__key__']) ) 962 { 963 if( $k != $v['__key__'] ) 964 { 965 $k = $v['__key__']; 966 if( ! strlen($k) || isset($a[ $k ]) ) 967 { // key already exists (or is empty): 968 $c = 1; 969 970 while( isset($a[ $k.'_'.$c ]) ) 971 { 972 $c++; 973 } 974 $k = $k.'_'.$c; 975 } 976 } 977 unset($v['__key__']); 978 979 $new_arr[$k] = $v; 980 } 981 else 982 { 983 $new_arr[$k] = $v; 984 } 985 986 // Recurse: 987 foreach( array_keys($v) as $rk ) 988 { 989 if( is_array($v[$rk]) ) 990 { 991 handle_array_keys_in_plugin_settings($v[$rk]); 992 } 993 } 994 } 995 $a = $new_arr; 996 } 997 998 999 /* 1000 * $Log: _plugin.funcs.php,v $ 1001 * Revision 1.2 2007/09/03 23:45:56 blueyed 1002 * Use always the array key as value for "select" settings. 1003 * 1004 * Revision 1.1 2007/06/25 11:00:42 fplanque 1005 * MODULES (refactored MVC) 1006 * 1007 * Revision 1.48 2007/06/19 20:40:26 fplanque 1008 * renamed generic functions to autoform_* 1009 * 1010 * Revision 1.47 2007/06/19 18:47:27 fplanque 1011 * Nuked unnecessary Param (or I'm missing something badly :/) 1012 * 1013 * Revision 1.46 2007/06/19 00:03:26 fplanque 1014 * doc / trying to make sense of automatic settings forms generation. 1015 * 1016 * Revision 1.45 2007/04/26 00:11:08 fplanque 1017 * (c) 2007 1018 * 1019 * Revision 1.44 2007/04/02 20:32:57 blueyed 1020 * Commented out block that caused problems 1021 * 1022 * Revision 1.43 2007/01/23 08:57:36 fplanque 1023 * decrap! 1024 * 1025 * Revision 1.42 2006/12/22 22:36:07 blueyed 1026 * Fixed selecting selected "None" option in "multiple" selects 1027 * 1028 * Revision 1.41 2006/12/22 22:29:35 blueyed 1029 * Support for "multiple" attribute in SELECT elements, especially for GetDefault(User)Settings plugin callback 1030 * 1031 * Revision 1.40 2006/12/10 12:36:58 blueyed 1032 * passthrough "rows" and "maxlength" attributes to input elements 1033 * 1034 * Revision 1.39 2006/12/09 01:55:36 fplanque 1035 * feel free to fill in some missing notes 1036 * hint: "login" does not need a note! :P 1037 * 1038 * Revision 1.38 2006/12/05 02:34:05 blueyed 1039 * Fix for "Minor refactoring".. :/ 1040 * 1041 * Revision 1.36 2006/12/05 01:59:12 blueyed 1042 * Added validation for all types of (User)Settings 1043 * 1044 * Revision 1.35 2006/12/04 22:26:06 blueyed 1045 * Fixed calling GetDefault(User)Settings with $params in set_Settings_for_Plugin_from_Request() 1046 * 1047 * Revision 1.34 2006/12/04 21:39:49 blueyed 1048 * Minor refactoring 1049 * 1050 * Revision 1.33 2006/12/01 16:47:26 blueyed 1051 * - Use EVO_NEXT_VERSION, which should get replaced with the next version 1.10 or 2.0 or whatever 1052 * - "action" param for PluginSettingsValidateSet 1053 * - Removed deprecated Plugin::set_param() 1054 * 1055 * Revision 1.32 2006/11/24 18:27:27 blueyed 1056 * Fixed link to b2evo CVS browsing interface in file docblocks 1057 * 1058 * Revision 1.31 2006/11/16 23:43:40 blueyed 1059 * - "key" entry for array-type Plugin(User)Settings can define an input field for the key of the settings entry 1060 * - cleanup 1061 * 1062 * Revision 1.30 2006/11/10 17:14:20 blueyed 1063 * Added "select_blog" type for Plugin (User)Settings 1064 * 1065 * Revision 1.29 2006/11/10 16:37:57 blueyed 1066 * Fixed ID for AJAX DIV 1067 * 1068 * Revision 1.28 2006/11/09 23:40:57 blueyed 1069 * Fixed Plugin UserSettings array type editing; Added jquery and use it for AJAHifying Plugin (User)Settings editing of array types 1070 * 1071 * Revision 1.27 2006/11/02 15:56:53 blueyed 1072 * Add note about having to save the settings, before adding a new set. 1073 * 1074 * Revision 1.26 2006/10/08 22:13:05 blueyed 1075 * Added "float" type to Plugin Setting types. 1076 */ 1077 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |