[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/etemplate/inc/ -> class.soetemplate.inc.php (source)

   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      


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7