[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare - EditableTemplates - Storage Objects * 4 * http://www.egroupware.org * 5 * Written by Ralf Becker <RalfBecker@outdoor-training.de> * 6 * -------------------------------------------- * 7 * This program is free software; you can redistribute it and/or modify it * 8 * under the terms of the GNU General Public License as published by the * 9 * Free Software Foundation; either version 2 of the License, or (at your * 10 * option) any later version. * 11 \**************************************************************************/ 12 13 /* $Id: class.soetemplate.inc.php 19740 2005-11-11 08:49:42Z ralfbecker $ */ 14 15 /** 16 * Storage Objects: Everything to store and retrive and eTemplate. 17 * 18 * eTemplates are stored in the db in table 'phpgw_etemplate' and gets distributed 19 * through the file 'etemplates.inc.php' in the setup dir of each app. That file gets 20 * automatically imported in the db, whenever you show a eTemplate of the app. For 21 * performace reasons the timestamp of the file is stored in the db, so 'new' 22 * eTemplates need to have a newer file. The distribution-file is generated with the 23 * function dump, usually by pressing a button in the editor. 24 * writeLangFile writes an lang-file with all Labels, incorporating an existing one. 25 * Beside a name eTemplates use the following keys to find the most suitable template 26 * for an user (in order of precedence): 27 * 1) User-/Group-Id (not yet implemented) 28 * 2) preferd languages of the user (templates for all langs have $lang='') 29 * 3) selected template: verdilak, ... (the default is called '' in the db, not default) 30 * 4) a version-number of the form, eg: '0.9.13.001' (filled up with 0 same size) 31 * 32 * @package etemplate 33 * @subpackage api 34 * @author RalfBecker-AT-outdoor-training.de 35 * @license GPL 36 */ 37 class soetemplate 38 { 39 var $debug; // =1 show some debug-messages, = 'app.name' show messages only for eTemplate 'app.name' 40 var $name; // name of the template, e.g. 'infolog.edit' 41 var $template; // '' = default (not 'default') 42 var $lang; // '' if general template else language short, e.g. 'de' 43 var $group; // 0 = not specific else groupId or if < 0 userId 44 var $version; // like 0.9.13.001 45 var $style; // embeded CSS style-sheet 46 var $children; // array with children 47 var $data; // depricated: first grid of the children 48 var $size; // depricated: witdh,height,border of first grid 49 var $db,$table_name = 'egw_etemplate'; // name of table 50 var $db_key_cols = array( 51 'et_name' => 'name', 52 'et_template' => 'template', 53 'et_lang' => 'lang', 54 'et_group' => 'group', 55 'et_version' => 'version' 56 ); 57 var $db_data_cols = array( 58 'et_data' => 'data', 59 'et_size' => 'size', 60 'et_style' => 'style', 61 'et_modified' => 'modified' 62 ); 63 var $db_cols; 64 /** 65 * @var array $widgets_with_children widgets that contain other widgets, eg. for tree_walk method 66 * widget-type is the key, the value specifys how the children are stored. 67 */ 68 var $widgets_with_children = array( 69 'template' => 'template', 70 'grid' => 'grid', 71 'box' => 'box', 72 'vbox' => 'box', 73 'hbox' => 'box', 74 'groupbox' => 'box', 75 'deck' => 'box', 76 ); 77 78 /** 79 * constructor of the class 80 * 81 * calls init or read depending on a name for the template is given 82 * 83 * @param string $name name of the eTemplate or array with the values for all keys 84 * @param string $template template-set, '' loads the prefered template of the user, 'default' loads the default one '' in the db 85 * @param string $lang language, '' loads the pref. lang of the user, 'default' loads the default one '' in the db 86 * @param int $group id of the (primary) group of the user or 0 for none, not used at the moment !!! 87 * @param string $version version of the eTemplate 88 * @param int $rows initial size of the template, default 1, only used if no name given !!! 89 * @param int $cols initial size of the template, default 1, only used if no name given !!! 90 */ 91 function soetemplate($name='',$template='',$lang='',$group=0,$version='',$rows=1,$cols=1) 92 { 93 $this->db = clone($GLOBALS['egw']->db); 94 $this->db->set_app('etemplate'); 95 $this->db_cols = $this->db_key_cols + $this->db_data_cols; 96 97 if (empty($name)) 98 { 99 $this->init($name,$template,$lang,$group,$version,$rows,$cols); 100 } 101 else 102 { 103 $this->read($name,$template,$lang,$group,$version); 104 } 105 } 106 107 /** 108 * generates column-names from index: 'A', 'B', ..., 'AA', 'AB', ..., 'ZZ' (not more!) 109 * 110 * @static 111 * @param int $num numerical index to generate name from 1 => 'A' 112 * @return string the name 113 */ 114 function num2chrs($num) 115 { 116 $min = ord('A'); 117 $max = ord('Z') - $min + 1; 118 if ($num >= $max) 119 { 120 $chrs = chr(($num / $max) + $min - 1); 121 } 122 $chrs .= chr(($num % $max) + $min); 123 124 return $chrs; 125 } 126 127 /** 128 * constructor for a new / empty cell/widget 129 * 130 * nothing fancy so far 131 * 132 * @static 133 * @param string $type type of the widget 134 * @param string $name name of widget 135 * @param array $attributes=null array with further attributes 136 * @return array the cell 137 */ 138 function empty_cell($type='label',$name='',$attributes=null) 139 { 140 $cell = array( 141 'type' => $type, 142 'name' => $name, 143 ); 144 if ($attributes && is_array($attributes)) 145 { 146 return array_merge($attributes,$cell); 147 } 148 return $cell; 149 } 150 151 /** 152 * constructs a new cell in a give row or the last row, not existing rows will be created 153 * 154 * @deprecated as it uses this->data 155 * @param int $row row-number starting with 1 (!) 156 * @param string $type type of the cell 157 * @param string $label label for the cell 158 * @param string $name name of the cell (index in the content-array) 159 * @param array $attributes other attributes for the cell 160 * @return array a reference to the new cell, use $new_cell = &$tpl->new_cell(); (!) 161 */ 162 function &new_cell($row=False,$type='label',$label='',$name='',$attributes=False) 163 { 164 $row = $row >= 0 ? intval($row) : 0; 165 if ($row && !isset($this->data[$row]) || !isset($this->data[1])) // new row ? 166 { 167 if (!$row) $row = 1; 168 169 $this->data[$row] = array(); 170 } 171 if (!$row) // use last row 172 { 173 $row = count($this->data); 174 while (!isset($this->data[$row])) 175 { 176 --$row; 177 } 178 } 179 $row = &$this->data[$row]; 180 $col = $this->num2chrs(count($row)); 181 $cell = &$row[$col]; 182 $cell = $this->empty_cell($type,$name); 183 if ($label !== '') 184 { 185 $attributes['label'] = $label; 186 } 187 if (is_array($attributes)) 188 { 189 foreach($attributes as $name => $value) 190 { 191 $cell[$name] = $value; 192 } 193 } 194 return $cell; 195 } 196 197 /** 198 * adds $cell to it's parent at the parent-type spezific location for childs 199 * 200 * @static 201 * @param array &$parent referenc to the parent 202 * @param array &$cell cell to add (need to be unset after the call to add_child, as it's a referenc !) 203 */ 204 function add_child(&$parent,&$cell) 205 { 206 if (is_object($parent)) // parent is the template itself 207 { 208 $parent->children[] = &$cell; 209 return; 210 } 211 switch($parent['type']) 212 { 213 case 'vbox': 214 case 'hbox': 215 case 'groupbox': 216 case 'box': 217 case 'deck': 218 list($n,$options) = explode(',',$parent['size'],2); 219 $parent[++$n] = &$cell; 220 $parent['size'] = $n . ($options ? ','.$options : ''); 221 break; 222 223 case 'grid': 224 $data = &$parent['data']; 225 $cols = &$parent['cols']; 226 $rows = &$parent['rows']; 227 $row = &$data[$rows]; 228 $col = count($row); 229 if (!$rows || !is_array($cell)) // create a new row 230 { 231 $row = &$data[++$rows]; 232 $row = array(); 233 } 234 if (is_array($cell)) // real cell to add 235 { 236 $row[soetemplate::num2chrs($col++)] = &$cell; 237 list($spanned) = explode(',',$cell['span']); 238 $spanned = $spanned == 'all' ? 1 + $cols - $col : $spanned; 239 while (--$spanned > 0) 240 { 241 $row[soetemplate::num2chrs($col++)] = soetemplate::empty_cell(); 242 } 243 if ($col > $cols) $cols = $col; 244 } 245 break; 246 } 247 } 248 249 /** 250 * initialises internal vars rows & cols from the data of a grid 251 * 252 * @static 253 * @param array &$grid to calc rows and cols 254 */ 255 function set_grid_rows_cols(&$grid) 256 { 257 $grid['rows'] = count($grid['data']) - 1; 258 $grid['cols'] = 0; 259 for($r = 1; $r <= $grid['rows']; ++$r) 260 { 261 $cols = count($grid['data'][$r]); 262 if ($grid['cols'] < $cols) 263 { 264 $grid['cols'] = $cols; 265 } 266 } 267 } 268 269 /** 270 * initialises internal vars rows & cols from the data of the first (!) grid 271 * 272 * @deprecated as it uses this->data 273 */ 274 function set_rows_cols() 275 { 276 if (is_null($this->data)) // tmpl contains no grid 277 { 278 $this->rows = $this->cols = 0; 279 } 280 else 281 { 282 $grid['data'] = &$this->data; 283 $grid['rows'] = &$this->rows; 284 $grid['cols'] = &$this->cols; 285 $this->set_grid_rows_cols($grid); 286 unset($grid); 287 } 288 } 289 290 /** 291 * initialises all internal data-structures of the eTemplate and sets the keys 292 * 293 * @param string $name name of the eTemplate or array with the values for all keys and possibly data 294 * @param string $template template-set or '' for the default one 295 * @param string $lang language or '' for the default one 296 * @param int $group id of the (primary) group of the user or 0 for none, not used at the moment !!! 297 * @param string $version version of the eTemplate 298 * @param int $rows initial size of the template, default 1 299 * @param int $cols initial size of the template, default 1 300 */ 301 function init($name='',$template='',$lang='',$group=0,$version='',$rows=1,$cols=1) 302 { 303 // unset children and data as they are referenzes to each other 304 unset($this->children); unset($this->data); 305 306 foreach($this->db_cols as $db_col => $col) 307 { 308 if ($col != 'data') $this->$col = is_array($name) ? (string) $name[$col] : $$col; 309 } 310 if ($this->template == 'default') 311 { 312 $this->template = ''; 313 } 314 if ($this->lang == 'default') 315 { 316 $this->lang = ''; 317 } 318 $this->tpls_in_file = is_array($name) ? $name['tpls_in_file'] : 0; 319 320 if (is_array($name) && $name['onclick_handler']) $this->onclick_handler = $name['onclick_handler']; 321 322 if (is_array($name) && isset($name['data'])) 323 { 324 // data/children are in $name['data'] 325 $this->children = is_array($name['data']) ? $name['data'] : unserialize($name['data']); 326 327 $this->fix_old_template_format(); 328 } 329 else 330 { 331 $this->size = $this->style = ''; 332 $this->data = array(0 => array()); 333 $this->rows = $rows < 0 ? 1 : $rows; 334 $this->cols = $cols < 0 ? 1 : $cols; 335 for ($row = 1; $row <= $rows; ++$row) 336 { 337 for ($col = 0; $col < $cols; ++$col) 338 { 339 $this->data[$row][$this->num2chrs($col)] = $this->empty_cell(); 340 } 341 } 342 $this->children[0]['type'] = 'grid'; 343 $this->children[0]['data'] = &$this->data; 344 $this->children[0]['rows'] = &$this->rows; 345 $this->children[0]['cols'] = &$this->cols; 346 $this->children[0]['size'] = &$this->size; 347 } 348 } 349 350 /** 351 * reads an eTemplate from the database 352 * 353 * @param string $name name of the eTemplate or array with the values for all keys 354 * @param string $template template-set, '' loads the prefered template of the user, 'default' loads the default one '' in the db 355 * @param string $lang language, '' loads the pref. lang of the user, 'default' loads the default one '' in the db 356 * @param int $group id of the (primary) group of the user or 0 for none, not used at the moment !!! 357 * @param string $version version of the eTemplate 358 * @return boolean True if a fitting template is found, else False 359 */ 360 function read($name,$template='default',$lang='default',$group=0,$version='') 361 { 362 $this->init($name,$template,$lang,$group,$version); 363 if ($this->debug == 1 || $this->debug == $this->name) 364 { 365 echo "<p>soetemplate::read('$this->name','$this->template','$this->lang',$this->group,'$this->version')</p>\n"; 366 } 367 if (($GLOBALS['egw_info']['server']['eTemplate-source'] == 'files' || 368 $GLOBALS['egw_info']['server']['eTemplate-source'] == 'xslt') && $this->readfile()) 369 { 370 return True; 371 } 372 if ($this->name) 373 { 374 $this->test_import($this->name); // import updates in setup-dir 375 } 376 $pref_lang = $GLOBALS['egw_info']['user']['preferences']['common']['lang']; 377 $pref_templ = $GLOBALS['egw_info']['server']['template_set']; 378 379 $where = array( 380 'et_name' => $this->name, 381 ); 382 if (is_array($name)) 383 { 384 $template = $name['template']; 385 } 386 if ($template == 'default') 387 { 388 $where[] = '(et_template='.$this->db->quote($pref_templ)." OR et_template='')"; 389 } 390 else 391 { 392 $where['et_template'] = $this->template; 393 } 394 if (is_array($name)) 395 { 396 $lang = $name['lang']; 397 } 398 if ($lang == 'default' || $name['lang'] == 'default') 399 { 400 $where[] = '(et_lang='.$this->db->quote($pref_lang)." OR et_lang='')"; 401 } 402 else 403 { 404 $where['et_lang'] = $this->lang; 405 } 406 if ($this->version != '') 407 { 408 $where['et_version'] = $this->version; 409 } 410 $this->db->select($this->table_name,'*',$where,__LINE__,__FILE__,false,'ORDER BY et_lang DESC,et_template DESC,et_version DESC'); 411 if (!$this->db->next_record()) 412 { 413 $version = $this->version; 414 return $this->readfile() && (empty($version) || $version == $this->version); 415 } 416 $this->db2obj(); 417 418 if ($this->debug == $this->name) 419 { 420 $this->echo_tmpl(); 421 } 422 return True; 423 } 424 425 /** 426 * Reads an eTemplate from the filesystem, the keys are already set by init in read 427 * 428 * @return boolean True if a template was found, else False 429 */ 430 function readfile() 431 { 432 list($app,$name) = explode('.',$this->name,2); 433 $template = $this->template == '' ? 'default' : $this->template; 434 435 if ($this->lang) 436 { 437 $lang = '.' . $this->lang; 438 } 439 $first_try = $ext = $GLOBALS['egw_info']['server']['eTemplate-source'] == 'xslt' ? '.xsl' : '.xet'; 440 441 while ((!$lang || !@file_exists($file = EGW_SERVER_ROOT . "/$app/templates/$template/$name$lang$ext") && 442 !@file_exists($file = EGW_SERVER_ROOT . "/$app/templates/default/$name$lang$ext")) && 443 !@file_exists($file = EGW_SERVER_ROOT . "/$app/templates/$template/$name$ext") && 444 !@file_exists($file = EGW_SERVER_ROOT . "/$app/templates/default/$name$ext")) 445 { 446 if ($ext == $first_try) 447 { 448 $ext = $ext == '.xet' ? '.xsl' : '.xet'; 449 450 if ($this->debug == 1 || $this->name != '' && $this->debug == $this->name) 451 { 452 echo "<p>tried '$file' now trying it with extension '$ext' !!!</p>\n"; 453 } 454 } 455 else 456 { 457 break; 458 } 459 } 460 if ($this->name == '' || $app == '' || $name == '' || !@file_exists($file) || !($f = @fopen($file,'r'))) 461 { 462 if ($this->debug == 1 || $this->name != '' && $this->debug == $this->name) 463 { 464 echo "<p>Can't open template '$this->name' / '$file' !!!</p>\n"; 465 } 466 return False; 467 } 468 $xml = fread ($f, filesize ($file)); 469 fclose($f); 470 471 if ($ext == '.xsl') 472 { 473 $cell = $this->empty_cell(); 474 $cell['type'] = 'xslt'; 475 $cell['size'] = $this->name; 476 //$cell['xslt'] = &$xml; xslttemplate class cant use it direct at the moment 477 $cell['name'] = ''; 478 $this->data = array(0 => array(),1 => array('A' => &$cell)); 479 $this->rows = $this->cols = 1; 480 } 481 else 482 { 483 if (!is_object($this->xul_io)) 484 { 485 $this->xul_io =& CreateObject('etemplate.xul_io'); 486 } 487 $loaded = $this->xul_io->import($this,$xml); 488 489 if (!is_array($loaded)) 490 { 491 return False; 492 } 493 $this->name = $app . '.' . $name; // if template was copied or app was renamed 494 495 $this->tpls_in_file = count($loaded); 496 } 497 return True; 498 } 499 500 /** 501 * Convert the usual *,? wildcards to the sql ones and quote %,_ 502 * 503 * @param string $pattern 504 * @return string 505 */ 506 function sql_wildcards($pattern) 507 { 508 return str_replace(array('%','_','*','?'),array('\\%','\\_','%','_'),$pattern); 509 } 510 511 /** 512 * Lists the eTemplates matching the given criteria, sql wildcards % and _ possible 513 * 514 * @param string $name name of the eTemplate or array with the values for all keys 515 * @param string $template template-set, '' loads the prefered template of the user, 'default' loads the default one '' in the db 516 * @param string $lang language, '' loads the pref. lang of the user, 'default' loads the default one '' in the db 517 * @param int $group id of the (primary) group of the user or 0 for none, not used at the moment !!! 518 * @param string $version version of the eTemplate 519 * @return array of arrays with the template-params 520 */ 521 function search($name,$template='default',$lang='default',$group=0,$version='') 522 { 523 if ($this->name) 524 { 525 $this->test_import($this->name); // import updates in setup-dir 526 } 527 if (is_array($name)) 528 { 529 $template = (string) $name['template']; 530 $lang = (string) $name['lang']; 531 $group = (int) $name['group']; 532 $version = (string) $name['version']; 533 $name = (string) $name['name']; 534 } 535 $where[] = 'et_name LIKE '.$this->db->quote($this->sql_wildcards($name).'%'); 536 if ($template != '' && $template != 'default') 537 { 538 $where[] = 'et_template LIKE '.$this->db->quote($this->sql_wildcards($template).'%'); 539 } 540 if ($lang != '' && $lang != 'default') 541 { 542 $where[] = 'et_lang LIKE '.$this->db->quote($this->sql_wildcards($lang).'%'); 543 } 544 if ($this->version != '') 545 { 546 $where[] = 'et_version LIKE '.$this->db->quote($this->sql_wildcards($version).'%'); 547 } 548 $this->db->select($this->table_name,'et_name,et_template,et_lang,et_group,et_version',$where,__LINE__,__FILE__,false,'ORDER BY et_name DESC,et_lang DESC,et_template DESC,et_version DESC'); 549 $result = array(); 550 while (($row = $this->db->row(true,'et_'))) 551 { 552 if ($row['lang'] != '##') // exclude or import-time-stamps 553 { 554 $result[] = $row; 555 } 556 } 557 if ($this->debug) 558 { 559 _debug_array($result); 560 } 561 return $result; 562 } 563 564 /** 565 * copies all cols into the obj and unserializes the data-array 566 */ 567 function db2obj() 568 { 569 // unset children and data as they are referenzes to each other 570 unset($this->children); unset($this->data); 571 572 foreach ($this->db_cols as $db_col => $name) 573 { 574 if ($name != 'data') 575 { 576 $this->$name = $this->db->f($db_col); 577 } 578 else 579 { 580 $this->children = unserialize($this->db->f($db_col)); 581 } 582 } 583 $this->fix_old_template_format(); 584 } 585 586 /** 587 * test if we have an old/original template-format and fixes it to the new format 588 */ 589 function fix_old_template_format() 590 { 591 if (!is_array($this->children)) $this->children = array(); 592 593 if (!isset($this->children[0]['type'])) 594 { 595 // old templates are treated as having one children of type grid (the original template) 596 $this->data = &$this->children; 597 unset($this->children); 598 599 $this->children[0]['type'] = 'grid'; 600 $this->children[0]['data'] = &$this->data; 601 $this->children[0]['rows'] = &$this->rows; 602 $this->children[0]['cols'] = &$this->cols; 603 $this->children[0]['size'] = &$this->size; 604 605 // that code fixes a bug in very old templates, not sure if it's still needed 606 if ($this->name[0] != '.' && is_array($this->data)) 607 { 608 reset($this->data); each($this->data); 609 while (list($row,$cols) = each($this->data)) 610 { 611 while (list($col,$cell) = each($cols)) 612 { 613 if (is_array($cell['type'])) 614 { 615 $this->data[$row][$col]['type'] = $cell['type'][0]; 616 //echo "corrected in $this->name cell $col$row attribute type<br>\n"; 617 } 618 if (is_array($cell['align'])) 619 { 620 $this->data[$row][$col]['align'] = $cell['align'][0]; 621 //echo "corrected in $this->name cell $col$row attribute align<br>\n"; 622 } 623 } 624 } 625 } 626 } 627 else 628 { 629 unset($this->data); 630 // for the moment we make $this->data as a referenz to the first grid 631 foreach($this->children as $key => $child) 632 { 633 if ($child['type'] == 'grid') 634 { 635 $this->data = &$this->children[$key]['data']; 636 $this->rows = &$this->children[$key]['rows']; 637 $this->cols = &$this->children[$key]['cols']; 638 if (!isset($this->children[$key]['size']) && !empty($this->size)) 639 { 640 $this->children[$key]['size'] = &$this->size; 641 } 642 else 643 { 644 $this->size = &$this->children[$key]['size']; 645 } 646 break; 647 } 648 } 649 } 650 $this->set_rows_cols(); 651 } 652 653 /** 654 * all empty values and objects in the array got unset (to save space in the db ) 655 * 656 * The never empty type field ensures a cell does not disapear completely. 657 * Calls it self recursivly for arrays / the rows 658 * 659 * @param array $arr the array to compress 660 * @param boolean $remove_all_objs if true unset all objs, on false use as_array to save only the data of objs 661 * @return array 662 */ 663 function compress_array($arr,$remove_objs=false) 664 { 665 if (!is_array($arr)) 666 { 667 return $arr; 668 } 669 foreach($arr as $key => $val) 670 { 671 if ($remove_objs && $key === 'obj') // it can be an array too 672 { 673 unset($arr[$key]); 674 } 675 elseif (is_array($val)) 676 { 677 $arr[$key] = $this->compress_array($val,$remove_objs); 678 } 679 elseif (!$remove_objs && $key == 'obj' && is_object($val) && method_exists($val,'as_array') && 680 // this test prevents an infinit recursion of templates calling itself, atm. etemplate.editor.new 681 $GLOBALS['egw_info']['etemplate']['as_array'][$this->name]++ < 2) 682 { 683 $arr['obj'] = $val->as_array(2); 684 } 685 elseif ($val == '' || is_object($val)) 686 { 687 unset($arr[$key]); 688 } 689 } 690 return $arr; 691 } 692 693 /** 694 * returns obj-data/-vars as array 695 * 696 * the returned array ($data_too > 0) can be used with init to recreate the template 697 * 698 * @param int $data_too -1 = only keys, 0 = no data array, 1 = data array too, 2 = serialize data array, 699 * 3 = only data values and data serialized 700 * @param boolean $db_keys use db-column-names or internal names, default false=internal names 701 * @return array with template-data 702 */ 703 function as_array($data_too=0,$db_keys=false) 704 { 705 //echo "<p>soetemplate::as_array($data_too,$db_keys) name='$this->name', ver='$this->version'</p>\n"; 706 $arr = array(); 707 switch($data_too) 708 { 709 case -1: 710 $cols = $this->db_key_cols; 711 break; 712 case 3: 713 $cols = $this->db_data_cols; 714 break; 715 default: 716 $cols = $this->db_cols; 717 } 718 foreach($cols as $db_col => $col) 719 { 720 if ($col == 'data') 721 { 722 if ($data_too > 0) 723 { 724 $arr[$db_keys ? $db_col : $col] = $data_too < 2 ? $this->children : 725 serialize($this->compress_array($this->children,$db_keys)); 726 } 727 } 728 else 729 { 730 $arr[$db_keys ? $db_col : $col] = $this->$col; 731 } 732 } 733 if ($data_too != -1 && $this->tpls_in_file && !$db_keys) 734 { 735 $arr['tpls_in_file'] = $this->tpls_in_file; 736 } 737 if ($data_too != -1 && $this->onclick_handler && !$db_keys) 738 { 739 $arr['onclick_handler'] = $this->onclick_handler; 740 } 741 return $arr; 742 } 743 744 /** 745 * saves eTemplate-object to db, can be used as saveAs by giving keys as params 746 * 747 * @param string $name name of the eTemplate or array with the values for all keys 748 * @param string $template template-set 749 * @param string $lang language or '' 750 * @param int $group id of the (primary) group, not used at the moment !!! 751 * @param string $version version of the eTemplate 752 * @return int number of affected rows, 1 should be ok, 0 somethings wrong 753 */ 754 function save($name='',$template='.',$lang='.',$group='',$version='.') 755 { 756 if (is_array($name)) 757 { 758 $template = $name['template']; 759 $lang = $name['lang']; 760 $group = $name['group']; 761 $version = $name['version']; 762 $name = $name['name']; 763 } 764 if ($name != '') 765 { 766 $this->name = $name; 767 } 768 if ($lang != '.') 769 { 770 $this->lang = $lang; 771 } 772 if ($template != '.') 773 { 774 $this->template = $template; 775 } 776 if ($group != '') 777 { 778 $this->group = $group; 779 } 780 if ($version != '.') 781 { 782 $this->version = $version; 783 } 784 if ($this->name == '') // name need to be set !!! 785 { 786 return False; 787 } 788 if ($this->debug > 0 || $this->debug == $this->name) 789 { 790 echo "<p>soetemplate::save('$this->name','$this->template','$this->lang',$this->group,'$this->version')</p>\n"; 791 } 792 if ($this->name[0] != '.' && is_array($this->data)) // correct old messed up templates 793 { 794 reset($this->data); each($this->data); 795 while (list($row,$cols) = each($this->data)) 796 { 797 while (list($col,$cell) = each($cols)) 798 { 799 if (is_array($cell['type'])) { 800 $this->data[$row][$col]['type'] = $cell['type'][0]; 801 //echo "corrected in $this->name cell $col$row attribute type<br>\n"; 802 } 803 if (is_array($cell['align'])) { 804 $this->data[$row][$col]['align'] = $cell['align'][0]; 805 //echo "corrected in $this->name cell $col$row attribute align<br>\n"; 806 } 807 } 808 } 809 } 810 if (!$this->modified) 811 { 812 $this->modified = time(); 813 } 814 if (is_null($this->group) && !is_int($this->group)) $this->group = 0; 815 816 $this->db->insert($this->table_name,$this->as_array(3,true),$this->as_array(-1,true),__LINE__,__FILE__); 817 818 $rows = $this->db->affected_rows(); 819 820 if (!$rows) 821 { 822 echo "<p>soetemplate::save('$this->name','$this->template','$this->lang',$this->group,'$this->version') <b>nothing written!!!</b></p>\n"; 823 function_backtrace(); 824 _debug_array($this->db); 825 } 826 return $rows; 827 } 828 829 /** 830 * Deletes the eTemplate from the db, object itself is unchanged 831 * 832 * @return int number of affected rows, 1 should be ok, 0 somethings wrong 833 */ 834 function delete() 835 { 836 $this->db->delete($this->table_name,$this->as_array(-1,true),__LINE__,__FILE__); 837 838 return $this->db->affected_rows(); 839 } 840 841 /** 842 * dumps all eTemplates to <app>/setup/etemplates.inc.php for distribution 843 * 844 * @param string $app app- or template-name contain app 845 * @return string translated message with number of dumped templates or error-message (webserver has no write access) 846 */ 847 function dump4setup($app) 848 { 849 list($app) = explode('.',$app); 850 851 $this->db->query("SELECT * FROM $this->table_name WHERE et_name LIKE '$app%'"); 852 853 $dir = EGW_SERVER_ROOT . "/$app/setup"; 854 if (!is_writeable($dir)) 855 { 856 return lang("Error: webserver is not allowed to write into '%1' !!!",$dir); 857 } 858 $file = "$dir/etemplates.inc.php"; 859 if (file_exists($file)) 860 { 861 $old_file = "$dir/etemplates.old.inc.php"; 862 if (file_exists($old_file)) 863 { 864 unlink($old_file); 865 } 866 rename($file,$old_file); 867 } 868 869 if (!($f = fopen($file,'w'))) 870 { 871 return 0; 872 } 873 fwrite($f,"<?php\n// eTemplates for Application '$app', generated by soetemplate::dump4setup() ".date('Y-m-d H:i')."\n\n". 874 '/* $'.'Id$ */'."\n\n\$templ_version=1;\n\n"); 875 876 for ($n = 0; $this->db->next_record(); ++$n) 877 { 878 $str = '$templ_data[] = array('; 879 foreach ($this->db_cols as $db_col => $name) 880 { 881 // escape only backslashes and single quotes (in that order) 882 $str .= "'$name' => '".str_replace(array('\\','\''),array('\\\\','\\\''),$this->db->f($db_col))."',"; 883 } 884 $str .= ");\n\n"; 885 fwrite($f,$str); 886 } 887 fclose($f); 888 889 return lang("%1 eTemplates for Application '%2' dumped to '%3'",$n,$app,$file); 890 } 891 892 /** 893 * extracts all texts: labels and helptexts from the cells of an eTemplate-object 894 * 895 * some extensions use a '|' to squezze multiple texts in a label or help field 896 * 897 * @return array with messages as key AND value 898 */ 899 function getToTranslate() 900 { 901 $to_trans = array(); 902 903 $this->widget_tree_walk('getToTranslateCell',$to_trans); 904 905 //echo '<b>'.$this->name.'</b>'; _debug_array($to_trans); 906 return $to_trans; 907 } 908 909 /** 910 * Read all eTemplates of an app an extracts the texts to an array 911 * 912 * @param string $app name of the app 913 * @return array with texts 914 */ 915 function getToTranslateApp($app) 916 { 917 $to_trans = array(); 918 919 $tpls = $this->search($app); 920 921 $tpl =& new soetemplate; // to not alter our own data 922 923 while (list(,$keys) = each($tpls)) 924 { 925 if (($keys['name'] != $last['name'] || // write only newest version 926 $keys['template'] != $last['template']) && 927 !strstr($keys['name'],'test')) 928 { 929 $tpl->read($keys); 930 $to_trans += $tpl->getToTranslate(); 931 $last = $keys; 932 } 933 } 934 return $to_trans; 935 } 936 937 /** 938 * Write new lang-file using the existing one and all text from the eTemplates 939 * 940 * @param string $app app- or template-name 941 * @param string $lang language the messages in the template are, defaults to 'en' 942 * @param array $additional extra texts to translate, if you pass here an array with all messages and 943 * select-options they get writen too (form is <unique key> => <message>) 944 * @return string translated message with number of messages written (total and new), or error-message 945 */ 946 function writeLangFile($app,$lang='en',$additional='') 947 { 948 if (!$additional) 949 { 950 $additional = array(); 951 } 952 list($app) = explode('.',$app); 953 954 if (!file_exists(EGW_SERVER_ROOT.'/developer_tools/inc/class.solangfile.inc.php')) 955 { 956 $solangfile =& CreateObject('etemplate.solangfile'); 957 } 958 else 959 { 960 $solangfile =& CreateObject('developer_tools.solangfile'); 961 } 962 $langarr = $solangfile->load_app($app,$lang); 963 if (!is_array($langarr)) 964 { 965 $langarr = array(); 966 } 967 $commonarr = $solangfile->load_app('phpgwapi',$lang) + $solangfile->load_app('etemplate',$lang); 968 969 $to_trans = $this->getToTranslateApp($app); 970 if (is_array($additional)) 971 { 972 //echo "writeLangFile: additional ="; _debug_array($additional); 973 foreach($additional as $msg) 974 { 975 if (!is_array($msg)) $to_trans[trim(strtolower($msg))] = $msg; 976 } 977 } 978 unset($to_trans['']); 979 980 for ($new = $n = 0; list($message_id,$content) = each($to_trans); ++$n) 981 { 982 if (!isset($langarr[$message_id]) && !isset($commonarr[$message_id])) 983 { 984 if (@isset($langarr[$content])) // caused by not lowercased-message_id's 985 { 986 unset($langarr[$content]); 987 } 988 $langarr[$message_id] = array( 989 'message_id' => $message_id, 990 'app_name' => $app, 991 'content' => $content 992 ); 993 ++$new; 994 } 995 } 996 ksort($langarr); 997 998 $dir = EGW_SERVER_ROOT . "/$app/setup"; 999 if (!is_writeable($dir)) 1000 { 1001 return lang("Error: webserver is not allowed to write into '%1' !!!",$dir); 1002 } 1003 $file = "$dir/phpgw_$lang.lang"; 1004 if (file_exists($file)) 1005 { 1006 $old_file = "$dir/phpgw_$lang.old.lang"; 1007 if (file_exists($old_file)) 1008 { 1009 unlink($old_file); 1010 } 1011 rename($file,$old_file); 1012 } 1013 $solangfile->write_file($app,$langarr,$lang); 1014 $solangfile->loaddb($app,$lang); 1015 1016 return lang("%1 (%2 new) Messages writen for Application '%3' and Languages '%4'",$n,$new,$app,$lang); 1017 } 1018 1019 /** 1020 * Imports the dump-file /$app/setup/etempplates.inc.php unconditional (!) 1021 * 1022 * @param string $app app name 1023 * @return string translated message with number of templates imported 1024 */ 1025 function import_dump($app) 1026 { 1027 $templ_version=0; 1028 1029 include($path = EGW_SERVER_ROOT."/$app/setup/etemplates.inc.php"); 1030 $templ =& new etemplate($app); 1031 1032 foreach($templ_data as $data) 1033 { 1034 if ((int)$templ_version < 1) // we need to stripslashes 1035 { 1036 $data['data'] = stripslashes($data['data']); 1037 } 1038 $templ->init($data); 1039 1040 if (!$templ->modified) 1041 { 1042 $templ->modified = filemtime($path); 1043 } 1044 $templ->save(); 1045 } 1046 return lang("%1 new eTemplates imported for Application '%2'",$n,$app); 1047 } 1048 1049 /** 1050 * test if new template-import necessary for app and does the import 1051 * 1052 * Get called on every read of a eTemplate, caches the result in phpgw_info. 1053 * The timestamp of the last import for app gets written into the db. 1054 * 1055 * @param string $app app- or template-name 1056 * @return string translated message with number of templates imported 1057 */ 1058 function test_import($app) // should be done from the setup-App 1059 { 1060 list($app) = explode('.',$app); 1061 1062 if (!$app || $GLOBALS['egw_info']['etemplate']['import_tested'][$app]) 1063 { 1064 return ''; // ensure test is done only once per call and app 1065 } 1066 $GLOBALS['egw_info']['etemplate']['import_tested'][$app] = True; // need to be done before new ... 1067 1068 $path = EGW_SERVER_ROOT."/$app/setup/etemplates.inc.php"; 1069 1070 if ($time = @filemtime($path)) 1071 { 1072 $templ =& new soetemplate(".$app",'','##'); 1073 if ($templ->lang != '##' || $templ->modified < $time) // need to import 1074 { 1075 $ret = $this->import_dump($app); 1076 $templ->modified = $time; 1077 $templ->save('.'.$app,'','##'); 1078 } 1079 } 1080 return $ret; 1081 } 1082 1083 /** 1084 * prints/echos the template's content, eg. for debuging 1085 * 1086 * @param boolean $backtrace = true give a function backtrace 1087 * @param boolean $no_other_objs = true dump other objs (db, html, ...) too 1088 */ 1089 function echo_tmpl($backtrace=true,$no_other_objs=true) 1090 { 1091 static $objs = array('db','html','xul_io'); 1092 1093 if ($backtrace) echo "<p>".function_backtrace(1)."</p>\n"; 1094 1095 if ($no_other_objs) 1096 { 1097 foreach($objs as $obj) 1098 { 1099 $$obj = &$this->$obj; 1100 unset($this->$obj); 1101 } 1102 } 1103 _debug_array($this); 1104 1105 if ($no_other_objs) 1106 { 1107 foreach($objs as $obj) 1108 { 1109 $this->$obj = &$$obj; 1110 unset($$obj); 1111 } 1112 } 1113 } 1114 1115 /** 1116 * applys a function to each widget in the children tree of the template 1117 * 1118 * The function should be defined as [&]func([&]$widget,[&]$extra[,$path]) 1119 * If the function returns anything but null or sets $extra['__RETURN__NOW__'] (func has to reference $extra !!!), 1120 * the walk stops imediatly and returns that result 1121 * 1122 * Only some widgets have a sub-tree of children: *box, grid, template, ... 1123 * For them we call tree_walk($widget,$func,$extra) instead of func direct 1124 * 1125 * @param string/array $func function to use or array($obj,'method') 1126 * @param mixed &$extra extra parameter passed to function 1127 * @return mixed return-value of func or null if nothing returned at all 1128 */ 1129 function &widget_tree_walk($func,&$extra) 1130 { 1131 if (!is_callable($func)) 1132 { 1133 echo "<p><b>boetemplate($this->name)::widget_tree_walk</b>(".print_r($func,true).", ".print_r($extra,true).", ".print_r($opts,true).") func is not callable !!!<br>".function_backtrace()."</p>"; 1134 return false; 1135 } 1136 $path = '/'; 1137 foreach($this->children as $c => $nul) 1138 { 1139 $child = &$this->children[$c]; 1140 if (isset($this->widgets_with_children[$child['type']])) 1141 { 1142 $result =& $this->tree_walk($child,$func,$extra,$path.$c); 1143 } 1144 else 1145 { 1146 $result =& $func($child,$extra,$path.$c); 1147 } 1148 if (!is_null($result) || is_array($extra) && isset($extra['__RETURN_NOW__'])) break; 1149 } 1150 return $result; 1151 } 1152 1153 /** 1154 * applys a function to each child in the tree of a widget (incl. the widget itself) 1155 * 1156 * The function should be defined as [&]func([&]$widget,[&]$extra[,$path]) [] = optional 1157 * If the function returns anything but null or sets $extra['__RETURN__NOW__'] (func has to reference $extra !!!), 1158 * the walk stops imediatly and returns that result 1159 * 1160 * Only some widgets have a sub-tree of children: *box, grid, template, ... 1161 * For performance reasons the function use recursion only if a widget with children contains 1162 * a further widget with children. 1163 * 1164 * @param array $widget the widget(-tree) the function should be applied too 1165 * @param string/array $func function to use or array($obj,'method') 1166 * @param mixed &$extra extra parameter passed to function 1167 * @param string $path path of widget in the widget-tree 1168 * @return mixed return-value of func or null if nothing returned at all 1169 */ 1170 function &tree_walk(&$widget,$func,&$extra,$path='') 1171 { 1172 if (!is_callable($func)) 1173 { 1174 echo "<p><b>boetemplate::tree_walk</b>(, ".print_r($func,true).", ".print_r($extra,true).", ".print_r($opts,true).") func is not callable !!!<br>".function_backtrace()."</p>"; 1175 return false; 1176 } 1177 $result =& $func($widget,$extra,$path); 1178 if (!is_null($result) || is_array($extra) && isset($extra['__RETURN__NOW__']) || 1179 !isset($this->widgets_with_children[$widget['type']])) 1180 { 1181 return $result; 1182 } 1183 switch($widget['type']) 1184 { 1185 case 'box': 1186 case 'vbox': 1187 case 'hbox': 1188 case 'groupbox': 1189 case 'deck': 1190 for($n = 1; is_array($widget[$n]); ++$n) 1191 { 1192 $child = &$widget[$n]; 1193 if (isset($this->widgets_with_children[$child['type']])) 1194 { 1195 $result =& $this->tree_walk($child,$func,$extra,$path.'/'.$n); 1196 } 1197 else 1198 { 1199 $result =& $func($child,$extra,$path.'/'.$n); 1200 } 1201 if (!is_null($result) || is_array($extra) && isset($extra['__RETURN__NOW__'])) return $result; 1202 } 1203 break; 1204 1205 case 'grid': 1206 $data = &$widget['data']; 1207 if (!is_array($data)) break; // no children 1208 1209 foreach($data as $r => $row) 1210 { 1211 if (!$r || !is_array($row)) continue; 1212 1213 foreach($row as $c => $col) 1214 { 1215 $child = &$data[$r][$c]; 1216 if (isset($this->widgets_with_children[$child['type']])) 1217 { 1218 $result =& $this->tree_walk($child,$func,$extra,$path.'/'.$r.$c); 1219 } 1220 else 1221 { 1222 $result =& $func($child,$extra,$path.'/'.$r.$c); 1223 } 1224 if (!is_null($result) || is_array($extra) && isset($extra['__RETURN__NOW__'])) return $result; 1225 unset($child); 1226 } 1227 } 1228 break; 1229 1230 case 'template': 1231 if (!isset($widget['obj']) && $widget['name'][0] != '@') 1232 { 1233 $widget['obj'] =& new etemplate; 1234 if (!$widget['obj']->read($widget['name'])) $widget['obj'] = false; 1235 } 1236 if (!is_object($widget['obj'])) break; // cant descent into template 1237 1238 $result =& $widget['obj']->widget_tree_walk($func,$extra); 1239 break; 1240 } 1241 return $result; 1242 } 1243 } 1244 1245 if (!function_exists('getToTranslateCell')) 1246 { 1247 /** 1248 * extracts all translatable labels from a widget 1249 * 1250 * @param array $cell the widget 1251 * @param array &$to_trans array with (lowercased) label => translation pairs 1252 */ 1253 function getToTranslateCell($cell,&$to_trans) 1254 { 1255 //echo $cell['name']; _debug_array($cell); 1256 $strings = explode('|',$cell['help']); 1257 1258 if ($cell['type'] != 'image') 1259 { 1260 $strings = array_merge($strings,explode('|',$cell['label'])); 1261 } 1262 list($extra_row) = explode(',',$cell['size']); 1263 if (substr($cell['type'],0,6) == 'select' && !empty($extra_row) && !intval($extra_row)) 1264 { 1265 $strings[] = $extra_row; 1266 } 1267 if (!empty($cell['blur'])) 1268 { 1269 $strings[] = $cell['blur']; 1270 } 1271 foreach($strings as $str) 1272 { 1273 if (strlen($str) > 1 && $str{0} != '@' && $str{0} != '$' && 1274 strstr($str,'$row') === false && strstr($str,'$cont') === false) 1275 { 1276 $to_trans[trim(strtolower($str))] = $str; 1277 } 1278 } 1279 } 1280 } 1281
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |