Logo Search packages:      
Sourcecode: egroupware version File versions  Download package

class.db_tools.inc.php

<?php
      /**************************************************************************\
      * eGroupWare - eTemplates - DB-Tools                                       *
      * http://www.egroupware.org                                                *
      * Written by Ralf Becker <RalfBecker@outdoor-training.de>                  *
      * --------------------------------------------                             *
      *  This program is free software; you can redistribute it and/or modify it *
      *  under the terms of the GNU General Public License as published by the   *
      *  Free Software Foundation; either version 2 of the License, or (at your  *
      *  option) any later version.                                              *
      \**************************************************************************/

      /* $Id: class.db_tools.inc.php,v 1.25.2.1 2004/08/08 09:19:06 ralfbecker Exp $ */

00015       class db_tools
      {
            var $public_functions = array
            (
                  'edit'         => True,
                  'needs_save'   => True,
                  //'admin'       => True,
                  //'preferences' => True
            );

            var $debug = 0;
            var $editor;      // editor eTemplate
            var $data;        // Table definitions
            var $app;         // used app
            var $table;       // used table
            var $types = array(
                  'varchar'   => 'varchar',
                  'int'       => 'int',
                  'auto'            => 'auto',
                  'blob'            => 'blob',
                  'char'            => 'char',
                  'date'            => 'date',
                  'decimal'   => 'decimal',
                  'float'           => 'float',
                  'longtext'  => 'longtext',
                  'text'            => 'text',
                  'timestamp' => 'timestamp',
//                'abstime'   => 'abstime (mysql:timestamp)',
            );
            var $setup_header = '<?php
  /**************************************************************************\\
  * eGroupWare - Setup                                                       *
  * http://www.eGroupWare.org                                                *
  * Created by eTemplates DB-Tools written by ralfbecker@outdoor-training.de *
  * --------------------------------------------                             *
  * This program is free software; you can redistribute it and/or modify it  *
  * under the terms of the GNU General Public License as published by the    *
  * Free Software Foundation; either version 2 of the License, or (at your   *
  * option) any later version.                                               *
  \\**************************************************************************/

  /* $Id: class.db_tools.inc.php,v 1.25.2.1 2004/08/08 09:19:06 ralfbecker Exp $ */
';

            /*!
            @function db_tools
            @syntax db_tools(  )
            @author ralfbecker
            @abstract constructor of class
            */
00065             function db_tools()
            {
                  $this->editor = CreateObject('etemplate.etemplate','etemplate.db-tools.edit');
                  $this->data = array();

                  if (!is_array($GLOBALS['phpgw_info']['apps']) || !count($GLOBALS['phpgw_info']['apps']))
                  {
                        ExecMethod('phpgwapi.applications.read_installed_apps');
                  }
                  $GLOBALS['phpgw_info']['flags']['app_header'] =
                        $GLOBALS['phpgw_info']['apps']['etemplate']['title'].' - '.lang('DB-Tools');
            }

            /*!
            @function edit
            @syntax edit( $content='',$msg='' )
            @author ralfbecker
            @abstract this is the table editor (and the callback/submit-method too)
            */
00084             function edit($content='',$msg = '')
            {
                  if (isset($_GET['app']))
                  {
                        $this->app = $_GET['app'];
                  }
                  if (is_array($content))
                  {
                        if ($this->debug)
                        {
                              echo "content ="; _debug_array($content);
                        }
                        $this->app = $content['app']; // this is what the user selected
                        $this->table = $content['table_name'];
                        $posted_app = $content['posted_app'];     // this is the old selection
                        $posted_table = $content['posted_table'];
                  }
                  if ($posted_app && $posted_table &&       // user changed app or table
                         ($posted_app != $this->app || $posted_table != $this->table))
                  {
                        if ($this->needs_save('',$posted_app,$posted_table,$this->content2table($content)))
                        {
                              return;
                        }
                        $this->renames = array();
                  }
                  if (!$this->app)
                  {
                        $this->table = '';
                        $table_names = array('' => lang('none'));
                  }
                  else
                  {
                        $this->read($this->app,$this->data);

                        foreach($this->data as $name => $table)
                        {
                              $table_names[$name] = $name;
                        }
                  }
                  if (!$this->table || $this->app != $posted_app)
                  {
                        reset($this->data);
                        list($this->table) = each($this->data);   // use first table
                  }
                  elseif ($this->app == $posted_app && $posted_table)
                  {
                        $this->data[$posted_table] = $this->content2table($content);
                  }
                  if ($content['write_tables'])
                  {
                        if ($this->needs_save('',$this->app,$this->table,$this->data[$posted_table]))
                        {
                              return;
                        }
                        $msg .= lang('Table unchanged, no write necessary !!!');
                  }
                  elseif ($content['delete'])
                  {
                        list($col) = each($content['delete']);

                        @reset($this->data[$posted_table]['fd']);
                        while ($col-- > 0 && list($key,$data) = @each($this->data[$posted_table]['fd'])) ;

                        unset($this->data[$posted_table]['fd'][$key]);
                        $this->changes[$posted_table][$key] = '**deleted**';
                  }
                  elseif ($content['add_column'])
                  {
                        $this->data[$posted_table]['fd'][''] = array();
                  }
                  elseif ($content['add_table'] || $content['import'])
                  {
                        if (!$this->app)
                        {
                              $msg .= lang('Select an app first !!!');
                        }
                        elseif (!$content['new_table_name'])
                        {
                              $msg .= lang('Please enter table-name first !!!');
                        }
                        elseif ($content['add_table'])
                        {
                              $this->table = $content['new_table_name'];
                              $this->data[$this->table] = array('fd' => array(),'pk' =>array(),'ix' => array(),'uc' => array(),'fk' => array());
                              $msg .= lang('New table created');
                        }
                        else // import
                        {
                              $oProc = CreateObject('phpgwapi.schema_proc',$GLOBALS['phpgw_info']['server']['db_type']);
                              $oProc->m_odb = $GLOBALS['phpgw']->db;
                              $oProc->m_oTranslator->_GetColumns($oProc,$content['new_table_name'],$nul);

                              while (list($key,$tbldata) = each ($oProc->m_oTranslator->sCol))
                              {
                                    $cols .= $tbldata;
                              }
                              eval('$cols = array('. $cols . ');');

                              $this->data[$this->table = $content['new_table_name']] = array(
                                    'fd' => $cols,
                                    'pk' => $oProc->m_oTranslator->pk,
                                    'fk' => $oProc->m_oTranslator->fk,
                                    'ix' => $oProc->m_oTranslator->ix,
                                    'uc' => $oProc->m_oTranslator->uc
                              );
                        }
                  }
                  elseif ($content['editor'])
                  {
                        ExecMethod('etemplate.editor.edit');
                        return;
                  }
                  $add_index = isset($content['add_index']);

                  // from here on, filling new content for eTemplate
                  $content = array(
                        'msg' => $msg,
                        'table_name' => $this->table,
                        'app' => $this->app,
                  );
                  if (!isset($table_names[$this->table]))   // table is not jet written
                  {
                        $table_names[$this->table] = $this->table;
                  }
                  $sel_options = array(
                        'table_name' => $table_names,
                        'type' => $this->types
                  );
                  if ($this->table != '' && isset($this->data[$this->table]))
                  {
                        $content += $this->table2content($this->data[$this->table],$sel_options['Index'],$add_index);
                  }
                  $no_button = array( );
                  if (!$this->app || !$this->table)
                  {
                        $no_button += array('write_tables' => True);
                  }
                  if ($this->debug)
                  {
                        echo 'editor.edit: content ='; _debug_array($content);
                  }
                  $this->editor->exec('etemplate.db_tools.edit',$content,$sel_options,$no_button,
                        array('posted_table' => $this->table,'posted_app' => $this->app,'changes' => $this->changes));
            }

            /*!
            @function needs_save
            @syntax needs_save( $cont='',$posted_app='',$posted_table='',$edited_table='' )
            @author ralfbecker
            @abstract checks if table was changed and if so offers user to save changes
            @param $cont the content of the form (if called by process_exec)
            @param $posted_app the app the table is from
            @param $posted_table the table-name
            @param $edited_table the edited table-definitions
            @result only if no changes
            */
00241             function needs_save($cont='',$posted_app='',$posted_table='',$edited_table='')
            {
                  if (!$posted_app && is_array($cont))
                  {
                        if (isset($cont['yes']))
                        {
                              $this->app   = $cont['app'];
                              $this->table = $cont['table'];
                              $this->read($this->app,$this->data);
                              $this->data[$this->table] = $cont['edited_table'];
                              $this->changes = $cont['changes'];
                              if ($cont['new_version'])
                              {
                                    $this->update($this->app,$this->data,$cont['new_version']);
                              }
                              else
                              {
                                    foreach($this->data as $tname => $tinfo)
                                    {
                                          $tables .= ($tables ? ',' : '') . "'$tname'";
                                    }
                                    $this->setup_version($this->app,'',$tables);
                              }
                              $msg .= $this->write($this->app,$this->data) ?
                                    lang('File writen') : lang('Error: writing file (no write-permission for the webserver) !!!');
                        }
                        $this->changes = array();
                        // return to edit with everything set, so the user gets the table he asked for
                        $this->edit(array(
                              'app' => $cont['new_app'],
                              'table_name' => $cont['app']==$cont['new_app'] ? $cont['new_table'] : '',
                              'posted_app' => $cont['new_app']
                        ),$msg);

                        return True;
                  }
                  $new_app   = $this->app;      // these are the ones, the users whiches to change too
                  $new_table = $this->table;

                  $this->app = $posted_app;
                  $this->data = array();
                  $this->read($posted_app,$this->data);

                  if (isset($this->data[$posted_table]) &&
                         $this->tables_identical($this->data[$posted_table],$edited_table))
                  {
                        if ($new_app != $this->app)   // are we changeing the app, or hit the user just write
                        {
                              $this->app = $new_app;  // if we change init the data empty
                              $this->data = array();
                        }
                        return False;     // continue edit
                  }
                  $content = array(
                        'app' => $posted_app,
                        'table' => $posted_table,
                        'version' => $this->setup_version($posted_app)
                  );
                  $preserv = $content + array(
                        'new_app' => $new_app,
                        'new_table' => $new_table,
                        'edited_table' => $edited_table,
                        'changes' => $this->changes
                  );
                  $new_version = explode('.',$content['version']);
                  $minor = count($new_version)-1;
                  $new_version[$minor] = sprintf('%03d',1+$new_version[$minor]);
                  $content['new_version'] = implode('.',$new_version);

                  $tmpl = new etemplate('etemplate.db-tools.ask_save');

                  if (!file_exists(PHPGW_SERVER_ROOT."/$posted_app/setup/tables_current.inc.php"))
                  {
                        $tmpl->disable_cells('version');
                        $tmpl->disable_cells('new_version');
                  }
                  $tmpl->exec('etemplate.db_tools.needs_save',$content,array(),array(),$preserv);

                  return True;      // dont continue in edit
            }

            /*!
            @function has_single_index
            @syntax has_single_index( $col,$index )
            @author ralfbecker
            @abstract checks if there is an index (only) on $col (not a multiple index incl. $col)
            @param $col column name
            @param $index ix or uc array of table-defintion
            @result True if $col has a single index
            */
00331             function has_single_index($col,$index,&$options)
            {
                  foreach($index as $in)
                  {
                        if ($in == $col || is_array($in) && $in[0] == $col && !isset($in[1]))
                        {
                              if ($in != $col && isset($in['options']))
                              {
                                    foreach($in['options'] as $db => $opts)
                                    {
                                          $options[] = $db.'('.(is_array($opts)?implode(',',$opts):$opts).')';
                                    }
                                    $options = implode(', ',$options);
                              }
                              return True;
                        }
                  }
                  return False;
            }

            /*!
            @function table2content
            @syntax table2content( $table )
            @author ralfbecker
            @abstract creates content-array from a $table
            @param $table table-definition, eg. $phpgw_baseline[$table_name]
            @result content-array
            */
00359             function table2content($table,&$columns,$extra_index=False)
            {
                  $content = $columns = array();
                  for ($n = 1; list($col_name,$col_defs) = each($table['fd']); ++$n)
                  {
                        $col_defs['name'] = $col_name;
                        $col_defs['pk'] = in_array($col_name,$table['pk']);
                        $col_defs['uc']  = $this->has_single_index($col_name,$table['uc'],$col_defs['options']);
                        $col_defs['ix'] = $this->has_single_index($col_name,$table['ix'],$col_defs['options']);
                        $col_defs['fk'] = $table['fk'][$col_name];
                        if (isset($col_defs['default']) && $col_defs['default'] == '')
                        {
                              $col_defs['default'] = is_int($col_defs['default']) ? '0' : "''"; // spezial value for empty, but set, default
                        }
                        $col_defs['notnull'] = isset($col_defs['nullable']) && !$col_defs['nullable'];

                        $col_defs['n'] = $n;

                        $content["Row$n"] = $col_defs;

                        $columns[$n] = $col_name;
                  }
                  $n = 2;
                  foreach(array('uc','ix') as $type)
                  {
                        foreach($table[$type] as $index)
                        {
                              if (is_array($index) && isset($index[1])) // multicolum index
                              {
                                    $content['Index'][$n]['unique'] = $type == 'uc';
                                    $content['Index'][$n]['n'] = $n - 1;
                                    foreach($index as $col)
                                    {
                                          $content['Index'][$n][] = array_search($col,$columns);
                                    }
                                    ++$n;
                              }
                        }
                  }
                  if ($extra_index)
                  {
                        $content['Index'][$n]['n'] = $n-1;
                  }
                  if ($this->debug >= 3)
                  {
                        echo "<p>table2content(,,'$extra_index'): content ="; _debug_array($content);
                        echo "<p>columns ="; _debug_array($columns);
                  }
                  return $content;
            }

            /*!
            @function content2table
            @syntax content2table( $content )
            @author ralfbecker
            @abstract creates table-definition from posted content
            @param $content posted content-array
            @note  It sets some reasonalbe defaults for not set precisions (else setup will not install)
            @result table-definition
            */
00419             function content2table($content)
            {
                  if (!is_array($this->data))
                  {
                        $this->read($content['posted_app'],$this->data);
                  }
                  $old_cols = $this->data[$posted_table = $content['posted_table']]['fd'];
                  $this->changes = $content['changes'];

                  $table = array();
                  $table['fd'] = array(); // do it in the default order of tables_*
                  $table['pk'] = array();
                  $table['fk'] = array();
                  $table['ix'] = array();
                  $table['uc'] = array();
                  for (reset($content),$n = 1; isset($content["Row$n"]); ++$n)
                  {
                        $col = $content["Row$n"];

                        while ((list($old_name,$old_col) = @each($old_cols)) &&
                               $this->changes[$posted_table][$old_name] == '**deleted**') ;

                        if (($name = $col['name']) != '')         // ignoring lines without column-name
                        {
                              if ($col['name'] != $old_name && $n <= count($old_cols))    // column renamed --> remeber it
                              {
                                    $this->changes[$posted_table][$old_name] = $col['name'];
                                    //echo "<p>content2table: $posted_table.$old_name renamed to $col[name]</p>\n";
                              }
                              if ($col['precision'] <= 0)
                              {
                                    switch ($col['type']) // set some defaults for precision, else setup fails
                                    {
                                          case 'float':
                                          case 'int':     $col['precision'] = 4; break;
                                          case 'char':    $col['precision'] = 1; break;
                                          case 'varchar': $col['precision'] = 255; break;
                                    }
                              }
                              while (list($prop,$val) = each($col))
                              {
                                    switch ($prop)
                                    {
                                          case 'default':
                                          case 'type':      // selectbox ensures type is not empty
                                          case 'precision':
                                          case 'scale':
//                                        case 'nullable':
                                                if ($val != '' || $prop == 'nullable')
                                                {
                                                      $table['fd'][$name][$prop] = $prop=='default'&& $val=="''" ? '' : $val;
                                                }
                                                break;
                                          case 'notnull':
                                                if ($val)
                                                {
                                                      $table['fd'][$name]['nullable'] = False;
                                                }
                                                break;
                                          case 'pk':
                                          case 'uc':
                                          case 'ix':
                                                if ($val)
                                                {
                                                      if ($col['options'])
                                                      {
                                                            $opts = array();
                                                            foreach(explode(',',$col['options']) as $opt)
                                                            {
                                                                  list($db,$opt) = split('[(:)]',$opt);
                                                                  $opts[$db] = is_numeric($opt) ? intval($opt) : $opt;
                                                            }
                                                            $table[$prop][] = array(
                                                                  $name,
                                                                  'options' => $opts
                                                            );
                                                      }
                                                      else
                                                      {
                                                            $table[$prop][] = $name;
                                                      }
                                                }
                                                break;
                                          case 'fk':
                                                if ($val != '')
                                                {
                                                      $table['fk'][$name] = $val;
                                                }
                                                break;
                                    }
                              }
                              $num2col[$n] = $col['name'];
                        }
                  }
                  foreach($content['Index'] as $n => $index)
                  {
                        $idx_arr = array();
                        foreach($index as $key => $num)
                        {
                              if (is_numeric($key) && $num && @$num2col[$num])
                              {
                                    $idx_arr[] = $num2col[$num];
                              }
                        }
                        if (count($idx_arr) && !isset($content['delete_index'][$n]))
                        {
                              if ($index['unique'])
                              {
                                    $table['uc'][] = $idx_arr;
                              }
                              else
                              {
                                    $table['ix'][] = $idx_arr;
                              }
                        }
                  }
                  if ($this->debug >= 2)
                  {
                        echo "<p>content2table: table ="; _debug_array($table);
                        echo "<p>changes = "; _debug_array($this->changes);
                  }
                  return $table;
            }

            /*!
            @function read
            @syntax read( $app,&$phpgw_baseline )
            @author ralfbecker
            @abstract includes $app/setup/tables_current.inc.php
            @param $app application name
            @param $phpgw_baseline where to put the data
            @result True if file found, False else
            */
00552             function read($app,&$phpgw_baseline)
            {
                  $file = PHPGW_SERVER_ROOT."/$app/setup/tables_current.inc.php";

                  $phpgw_baseline = array();

                  if ($app != '' && file_exists($file))
                  {
                        include($file);
                  }
                  else
                  {
                        return False;
                  }
                  if ($this->debug >= 5)
                  {
                        echo "<p>read($app): file='$file', phpgw_baseline =";
                        _debug_array($phpgw_baseline);
                  }
                  return True;
            }

            function write_array($arr,$depth,$parent='')
            {
                  if (in_array($parent,array('pk','fk','ix','uc')))
                  {
                        $depth = 0;
                  }
                  if ($depth)
                  {
                        $tabs = "\n";
                        for ($n = 0; $n < $depth; ++$n)
                        {
                              $tabs .= "\t";
                        }
                        ++$depth;
                  }
                  $def = "array($tabs".($tabs ? "\t" : '');

                  $n = 0;
                  foreach($arr as $key => $val)
                  {
                        if (!is_int($key))
                        {
                              $def .= "'$key' => ";
                        }
                        if (is_array($val))
                        {
                              $def .= $this->write_array($val,$parent == 'fd' ? 0 : $depth,$key);
                        }
                        else
                        {
                              if (!$only_vals && $key === 'nullable')
                              {
                                    $def .= $val ? 'True' : 'False';
                              }
                              else
                              {
                                    $def .= "'$val'";
                              }
                        }
                        if ($n < count($arr)-1)
                        {
                              $def .= ",$tabs".($tabs ? "\t" : '');
                        }
                        ++$n;
                  }
                  $def .= "$tabs)";

                  return $def;
            }

            /*!
            @function write
            @syntax write( $app,$phpgw_baseline )
            @author ralfbecker
            @abstract writes tabledefinitions $phpgw_baseline to file /$app/setup/tables_current.inc.php
            @param $app app-name
            @param $phpgw_baseline tabledefinitions
            @return True if file writen else False
            */
00633             function write($app,$phpgw_baseline)
            {
                  $file = PHPGW_SERVER_ROOT."/$app/setup/tables_current.inc.php";

                  if (file_exists($file) && ($f = fopen($file,'r')))
                  {
                        $header = fread($f,filesize($file));
                        if ($end = strpos($header,');'))
                        {
                              $footer = substr($header,$end+3);   // this preservs other stuff, which should not be there
                        }
                        $header = substr($header,0,strpos($header,'$phpgw_baseline'));
                        fclose($f);

                        if (is_writable(PHPGW_SERVER_ROOT."/$app/setup"))
                        {
                              $old_file = PHPGW_SERVER_ROOT . "/$app/setup/tables_current.old.inc.php";
                              if (file_exists($old_file))
                              {
                                    unlink($old_file);
                              }
                              rename($file,$old_file);
                        }
                        while ($header[strlen($header)-1] == "\t")
                        {
                              $header = substr($header,0,strlen($header)-1);
                        }
                  }
                  if (!$header)
                  {
                        $header = $this->setup_header . "\n\n";
                  }
                  if (!is_writeable(PHPGW_SERVER_ROOT."/$app/setup") || !($f = fopen($file,'w')))
                  {
                        return False;
                  }
                  $def .= "\t\$phpgw_baseline = ";
                  $def .= $this->write_array($phpgw_baseline,1);
                  $def .= ";\n";

                  fwrite($f,$header . $def . $footer);
                  fclose($f);

                  return True;
            }

            /*!
            @function setup_version
            @syntax setup_version( $app,$new = '',$tables='' )
            @author ralfbecker
            @abstract reads and updates the version and tables info in file $app/setup/setup.inc.php
            @param $app the app
            @param $new new version number to set, if $new != ''
            @param $tables new tables to include, if $tables != ''
            @return the version or False if the file could not be read or written
            */
00689             function setup_version($app,$new = '',$tables='')
            {
                  //echo "<p>etemplate.db_tools.setup_version('$app','$new','$tables')</p>\n";

                  $file = PHPGW_SERVER_ROOT."/$app/setup/setup.inc.php";
                  if (file_exists($file))
                  {
                        include($file);
                  }
                  if (!is_array($setup_info[$app]) || !isset($setup_info[$app]['version']))
                  {
                        return False;
                  }
                  if (($new == '' || $setup_info[$app]['version'] == $new) && 
                      (!$tables || $setup_info[$app]['tables'] && "'".implode("','",$setup_info[$app]['tables'])."'" == $tables))
                  {
                        return $setup_info[$app]['version'];      // no change requested or not necessary 
                  }
                  if ($new == '') 
                  {
                        $new = $setup_info[$app]['version'];
                  }
                  if (!($f = fopen($file,'r')))
                  {
                        return False;
                  }
                  $fcontent = fread($f,filesize($file));
                  fclose ($f);

                  if (is_writable(PHPGW_SERVER_ROOT."/$app/setup"))
                  {
                        $old_file = PHPGW_SERVER_ROOT . "/$app/setup/setup.old.inc.php";
                        if (file_exists($old_file))
                        {
                              unlink($old_file);
                        }
                        rename($file,$old_file);
                  }
                  $fnew = preg_replace('/(.*\\$'."setup_info\\['$app'\\]\\['version'\\][ \\t]*=[ \\t]*)'[^']*'(.*)/i","\\1'$new'\\2",$fcontent);
                  
                  if ($tables != '')
                  {
                        if ($setup_info[$app]['tables'])    // if there is already tables array, update it
                        {
                              $fnew = preg_replace('/(.*\\$'."setup_info\\['$app'\\]\\['tables'\\][ \\t]*=[ \\t]*array\()[^)]*/i","\\1$tables",$fwas=$fnew);

                              if ($fwas == $fnew)     // nothing changed => tables are in single lines
                              {
                                    $fwas = explode("\n",$fwas);
                                    $fnew = $prefix = '';
                                    $stage = 0; // 0 = before, 1 = in, 2 = after tables section
                                    foreach($fwas as $line)
                                    {
                                          if (preg_match('/(.*\\$'."setup_info\\['$app'\\]\\['tables'\\]\\[[ \\t]*\\][ \\t]*=[ \\t]*)'/i",$line,$parts))
                                          {
                                                if ($stage == 0)  // first line of tables-section
                                                {
                                                      $stage = 1;
                                                      $prefix = $parts[1];
                                                }
                                          }
                                          else                          // not in table-section
                                          {
                                                if ($stage == 1)  // first line after tables-section ==> add it
                                                {
                                                      $tables = explode(',',$tables);
                                                      foreach ($tables as $table)
                                                      {
                                                            $fnew .= $prefix . $table . ";\n";
                                                      }
                                                      $stage = 2; 
                                                }
                                                if (strpos($line,'?>') === False)   // dont write the closeing tag
                                                {
                                                      $fnew .= $line . "\n";
                                                }
                                          }
                                    }
                              }
                        }
                        else  // add the tables array
                        {
                              if (strstr($fnew,'?>')) // remove a closeing tag
                              {
                                    $fnew = str_replace('?>','',$fnew);
                              }
                              $fnew .= "\t\$setup_info['$app']['tables'] = array($tables);\n";
                        }
                  }
                  if (!is_writeable(PHPGW_SERVER_ROOT."/$app/setup") || !($f = fopen($file,'w')))
                  {
                        return False;
                  }
                  fwrite($f,$fnew);
                  fclose($f);

                  return $new;
            }

            /*!
            @function update
            @syntax update( $app,$current,$version )
            @author ralfbecker
            @abstract updates file /$app/setup/tables_update.inc.php to reflect changes in $current
            @param $app app-name
            @param $current new tabledefinitions
            @param $version new version
            @return True if file writen else False
            */
00798             function update($app,$current,$version)
            {
                  //echo "<p>etemplate.db_tools.update('$app',...,'$version')</p>\n";

                  if (!is_writable(PHPGW_SERVER_ROOT."/$app/setup"))
                  {
                        return False;
                  }
                  $file_baseline = PHPGW_SERVER_ROOT."/$app/setup/tables_baseline.inc.php";
                  $file_current  = PHPGW_SERVER_ROOT."/$app/setup/tables_current.inc.php";
                  $file_update   = PHPGW_SERVER_ROOT."/$app/setup/tables_update.inc.php";

                  if (!file_exists($file_baseline) && !copy($file_current,$file_baseline))
                  {
                        //echo "<p>Can't copy $file_current to $file_baseline !!!</p>\n";
                        return False;
                  }
                  $old_version = $this->setup_version($app);
                  $old_version_ = str_replace('.','_',$old_version);

                  if (file_exists($file_update))
                  {
                        $f = fopen($file_update,'r');
                        $update = fread($f,filesize($file_update));
                        $update = str_replace('?>','',$update);
                        fclose($f);
                        $old_file = PHPGW_SERVER_ROOT . "/$app/setup/tables_update.old.inc.php";
                        if (file_exists($old_file))
                        {
                              unlink($old_file);
                        }
                        rename($file_update,$old_file);
                  }
                  else
                  {
                        $update = $this->setup_header;
                  }
                  $update .= "
      \$test[] = '$old_version';
      function $app"."_upgrade$old_version_()
      {\n";

                  $update .= $this->update_schema($app,$current,$tables);

                  $update .= "
            \$GLOBALS['setup_info']['$app']['currentver'] = '$version';
            return \$GLOBALS['setup_info']['$app']['currentver'];
      }
?".">\n";
                  if (!($f = fopen($file_update,'w')))
                  {
                        //echo "<p>Cant open '$update' for writing !!!</p>\n";
                        return False;
                  }
                  fwrite($f,$update);
                  fclose($f);

                  $this->setup_version($app,$version,$tables);

                  return True;
            }

            function remove_from_array(&$arr,$value)
            {
                  foreach($arr as $key => $val)
                  {
                        if ($val == $value)
                        {
                              unset($arr[$key]);
                        }
                  }
            }

            function update_schema($app,$current,&$tables)
            {
                  $this->read($app,$old);

                  $tables = '';
                  foreach($old as $name => $table_def)
                  {
                        if (!isset($current[$name]))  // table $name droped
                        {
                              $update .= "\t\t\$GLOBALS['phpgw_setup']->oProc->DropTable('$name');\n";
                        }
                        else
                        {
                              $tables .= ($tables ? ',' : '') . "'$name'";

                              $new_table_def = $table_def;
                              foreach($table_def['fd'] as $col => $col_def)
                              {
                                    if (!isset($current[$name]['fd'][$col]))  // column $col droped
                                    {
                                          if (!isset($this->changes[$name][$col]) || $this->changes[$name][$col] == '**deleted**')
                                          {
                                                unset($new_table_def['fd'][$col]);
                                                $this->remove_from_array($new_table_def['pk'],$col);
                                                $this->remove_from_array($new_table_def['fk'],$col);
                                                $this->remove_from_array($new_table_def['ix'],$col);
                                                $this->remove_from_array($new_table_def['uc'],$col);
                                                $update .= "\t\t\$GLOBALS['phpgw_setup']->oProc->DropColumn('$name',";
                                                $update .= $this->write_array($new_table_def,2).",'$col');\n";
                                          }
                                          else  // column $col renamed
                                          {
                                                $new_col = $this->changes[$name][$col];
                                                $update .= "\t\t\$GLOBALS['phpgw_setup']->oProc->RenameColumn('$name','$col','$new_col');\n";
                                          }
                                    }
                              }
                              if (is_array($this->changes[$name]))
                              {
                                    foreach($this->changes[$name] as $col => $new_col)
                                    {
                                          if ($new_col != '**deleted**')
                                          {
                                                $old[$name]['fd'][$new_col] = $old[$name]['fd'][$col];      // to be able to detect further changes of the definition
                                                unset($old[$name]['fd'][$col]);
                                          }
                                    }
                              }
                        }
                  }
                  foreach($current as $name => $table_def)
                  {
                        if (!isset($old[$name]))      // table $name added
                        {
                              $tables .= ($tables ? ',' : '') . "'$name'";

                              $update .= "\t\t\$GLOBALS['phpgw_setup']->oProc->CreateTable('$name',";
                              $update .= $this->write_array($table_def,2).");\n";
                        }
                        else
                        {
                              $old_norm = $this->normalize($old[$name]);
                              $new_norm = $this->normalize($table_def);
                              $old_norm_fd = $old_norm['fd']; unset($old_norm['fd']);
                              $new_norm_fd = $new_norm['fd']; unset($new_norm['fd']);

                              // check if the indices are changed and refresh the table if so
                              $do_refresh = serialize($old_norm) != serialize($new_norm);
                              // we comment out the Add or AlterColumn code as it is not needed, but might be useful for more complex updates
                              foreach($table_def['fd'] as $col => $col_def)
                              {
                                    if (($add = !isset($old[$name]['fd'][$col])) || // column $col added
                                           serialize($old_norm_fd[$col]) != serialize($new_norm_fd[$col])) // column definition altered
                                    {
                                          $update .= "\t\t".($do_refresh ? "/* done by RefreshTable() anyway\n\t\t" : '').
                                                "\$GLOBALS['phpgw_setup']->oProc->".($add ? 'Add' : 'Alter')."Column('$name','$col',";
                                          $update .= $this->write_array($col_def,2) . ');' . ($do_refresh ? '*/' : '') . "\n";
                                    }
                              }
                              if ($do_refresh)
                              {
                                    $update .= "\t\t\$GLOBALS['phpgw_setup']->oProc->RefreshTable('$name',";
                                    $update .= $this->write_array($table_def,2).");\n";
                              }
                        }
                  }
                  if ($this->debug)
                  {
                        echo "<p>update_schema($app, ...) =<br><pre>$update</pre>)</p>\n";
                  }
                  return $update;
            }

            /*!
            @function normalize_index
            @abstract orders the single-colum-indices after the columns and the multicolunm ones bedind
            @syntax normalize_index( $index,$cols )
            @param index array with indices
            @param cols  array with column-defs (col-name in key)
            @author ralfbecker
            @result the new array
            */
00973             function normalize_index($index,$cols)
            {
                  $normalized = array();
                  foreach($cols as $col => $data)
                  {
                        foreach($index as $n => $idx)
                        {
                              if ($idx == $col || is_array($idx) && $idx[0] == $col && !isset($idx[1]))
                              {
                                    $normalized[] = isset($idx['options']) ? $idx : $col;
                                    unset($index[$n]);
                                    break;
                              }
                        }
                  }
                  foreach($index as $idx)
                  {
                        $normalized[] = $idx;
                  }
                  return $normalized;
            }

            /*!
            @function normalize
            @syntax normalize( $table )
            @author ralfbecker
            @abstract sets all nullable properties to True or False
            @result the new array
            */
01002             function normalize($table)
            {
                  $all_props = array('type','precision','nullable','default');

                  foreach($table['fd'] as $col => $props)
                  {
                        $table['fd'][$col] = array(
                              'type' => ''.$props['type'],
                              'precision' => 0+$props['precision'],
                              'scale' => 0+$props['scale'],
                              'nullable' => !isset($props['nullable']) || !!$props['nullable'],
                              'default' => ''.$props['default']
                        );
                  }
                  return array(
                        'fd' => $table['fd'],
                        'pk' => $table['pk'],
                        'fk' => $table['fk'],
                        'ix' => $this->normalize_index($table['ix'],$table['fd']),
                        'uc' => $this->normalize_index($table['uc'],$table['fd'])
                  );
            }

            /*!
            @function tables_identical
            @syntax tables_identical( $old,$new )
            @author ralfbecker
            @abstract compares two table-definitions
            @result True if they are identical or False else
            */
01032             function tables_identical($a,$b)
            {
                  $a = serialize($this->normalize($a));
                  $b = serialize($this->normalize($b));

                  //echo "<p>checking if tables identical = ".($a == $b ? 'True' : 'False')."<br>\n";
                  //echo "a: $a<br>\nb: $b</p>\n";

                  return $a == $b;
            }
      }




Generated by  Doxygen 1.6.0   Back to index