* all apps: custom-fields are now stored in own egw_customfields table (no more limit on number), site configurations get now JSON serialized

This commit is contained in:
Ralf Becker 2014-06-23 14:35:22 +00:00
parent ae19dff1d4
commit ffae12e240
12 changed files with 449 additions and 126 deletions

View File

@ -78,7 +78,7 @@ class admin_cmd_change_account_id extends admin_cmd
}
// we have a custom field table and cfs containing accounts
if ($cf && !empty($cf['cfname']) && !empty($cf['cfvalue']) &&
($account_cfs = config::get_account_cfs($app == 'phpgwapi' ? 'addressbook' : $app)))
($account_cfs = egw_customfields::get_account_cfs($app == 'phpgwapi' ? 'addressbook' : $app)))
{
foreach($account_cfs as $type => $names)
{
@ -172,7 +172,7 @@ class admin_cmd_change_account_id extends admin_cmd
{
foreach($GLOBALS['egw_info']['apps'] as $app => $data)
{
$total += ($changed = config::change_account_ids($app, $this->change));
$total += ($changed = egw_customfields::change_account_ids($app, $this->change));
if ($changed) echo "$app:\t$changed id's in definition of private custom fields changed\n";
}
}

View File

@ -52,7 +52,7 @@ class customfields
{
if (($this->appname = $appname))
{
$this->fields = config::get_customfields($this->appname,true);
$this->fields = egw_customfields::get($this->appname,true);
$this->content_types = config::get_content_types($this->appname);
}
}
@ -73,7 +73,7 @@ class customfields
$this->tmpl = new etemplate();
// do we manage content-types?
if($this->tmpl->read($this->appname.'.admin.types')) $this->manage_content_types = true;
$this->fields = config::get_customfields($this->appname,true);
$this->fields = egw_customfields::get($this->appname,true);
$this->tmpl->read('admin.customfields');
if($this->manage_content_types)
@ -381,22 +381,23 @@ class customfields
//echo '<p>uicustomfields::save_repository() \$this->fields=<pre style="text-aling: left;">'; print_r($this->fields); echo "</pre>\n";
$config = new config($this->appname);
$config->read_repository();
$config->value('customfields',$this->fields);
$config->value('types',$this->content_types);
$config->save_repository();
egw_customfields::save($this->appname, $this->fields);
}
/**
* get customfields of using application
*
* @deprecated use config::get_customfields() direct, no need to instanciate this UI class
* @deprecated use egw_customfields::get() direct, no need to instanciate this UI class
* @author Cornelius Weiss
* @param boolean $all_private_too=false should all the private fields be returned too
* @return array with customfields
*/
function get_customfields($all_private_too=false)
{
return config::get_customfields($this->appname,$all_private_too);
return egw_customfields::get($this->appname,$all_private_too);
}
/**

View File

@ -91,7 +91,7 @@ class customfields_widget
function __construct($ui=null,$appname=null)
{
$this->appname = $appname ? $appname : $GLOBALS['egw_info']['flags']['currentapp'];
$this->customfields = config::get_customfields($this->appname);
$this->customfields = egw_customfields::get($this->appname);
$this->types = config::get_content_types($this->appname);
$this->advanced_search = $GLOBALS['egw_info']['etemplate']['advanced_search'];
}
@ -561,7 +561,7 @@ class customfields_widget
{
$link_types = self::get_customfield_link_types();
foreach(config::get_customfields($own_app) as $name => $data)
foreach(egw_customfields::get($own_app) as $name => $data)
{
if (!in_array($data['type'],$link_types)) continue;

View File

@ -113,7 +113,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
if(!$app)
{
$app =& $this->setElementAttribute(self::GLOBAL_VALS, 'app', $GLOBALS['egw_info']['flags']['currentapp']);
$customfields =& $this->setElementAttribute(self::GLOBAL_VALS, 'customfields', config::get_customfields($app));
$customfields =& $this->setElementAttribute(self::GLOBAL_VALS, 'customfields', egw_customfields::get($app));
}
// if we are in the etemplate editor or the app has no cf's, load the cf's from the app the tpl belongs too
@ -123,7 +123,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
))
{
// app changed
$customfields =& config::get_customfields($app);
$customfields =& egw_customfields::get($app);
}
// Filter fields

View File

@ -164,7 +164,7 @@ class so_sql_cf extends so_sql
$this->extra_join_order = " LEFT JOIN $extra_table extra_order ON $table.$this->autoinc_id=extra_order.$this->extra_id";
$this->extra_join_filter = " JOIN $extra_table extra_filter ON $table.$this->autoinc_id=extra_filter.$this->extra_id";
$this->customfields = config::get_customfields($app);
$this->customfields = egw_customfields::get($app);
}
/**

View File

@ -225,7 +225,7 @@ class infolog_bo
}
if ($config_data['group_owners']) $this->group_owners = $config_data['group_owners'];
$this->customfields = config::get_customfields('infolog');
$this->customfields = egw_customfields::get('infolog');
if ($this->customfields)
{
foreach($this->customfields as $name => $field)
@ -830,7 +830,7 @@ class infolog_bo
// Check required custom fields
if($throw_exception)
{
$custom = config::get_customfields('infolog');
$custom = egw_customfields::get('infolog');
foreach($custom as $c_name => $c_field)
{
if($c_field['type2']) $type2 = explode(',',$c_field['type2']);

View File

@ -368,7 +368,7 @@ class infolog_customfields
//echo '<p>'.__METHOD__.'() \$this->status=<pre style="text-aling: left;">'; print_r($this->status); echo "</pre>\n";
config::save_value('status',$this->status,'infolog');
//echo '<p>'.__METHOD__.'() \$this->fields=<pre style="text-aling: left;">'; print_r($this->fields); echo "</pre>\n";
config::save_value('customfields',$this->fields,'infolog');
egw_customfields::save('infolog', $this->fields);
config::save_value('group_owners',$this->group_owners,'infolog');
}
}

View File

@ -10,6 +10,8 @@
/**
* eGW's application configuration in a centralized location
*
* New config values are stored JSON serialized now instead of PHP serialized before 14.1.
*/
class config
{
@ -150,7 +152,7 @@ class config
else
{
self::$configs[$app][$name] = $value;
if(is_array($value)) $value = serialize($value);
if(is_array($value)) $value = json_encode($value);
self::$db->insert(config::TABLE,array('config_value'=>$value),array('config_app'=>$app,'config_name'=>$name),__LINE__,__FILE__);
}
if ($update_cache)
@ -224,106 +226,13 @@ class config
* @param string $app
* @param boolean $all_private_too=false should all the private fields be returned too, default no
* @param string $only_type2=null if given only return fields of type2 == $only_type2
* @deprecated use egw_customfields::get()
* @return array with customfields
*/
static function get_customfields($app,$all_private_too=false, $only_type2=null)
static function get_customfields($app, $all_private_too=false, $only_type2=null)
{
$config = self::read($app);
$config_name = isset($config['customfields']) ? 'customfields' : 'custom_fields';
$cfs = is_array($config[$config_name]) ? $config[$config_name] : array();
foreach($cfs as $name => $field)
{
if (!$all_private_too && $field['private'] && !self::_check_private_cf($field['private']) ||
$only_type2 && $field['type2'] && !in_array($only_type2, is_array($field['type2']) ? $field['type2'] : explode(',', $field['type2'])))
{
unset($cfs[$name]);
}
}
//error_log(__METHOD__."('$app', $all_private_too, '$only_type2') returning fields: ".implode(', ', array_keys($cfs)));
return $cfs;
}
/**
* Check if user is allowed to see a certain private cf
*
* @param string $private comma-separated list of user- or group-id's
* @return boolean true if user has access, false otherwise
*/
private static function _check_private_cf($private)
{
static $user_and_memberships = null;
if (!$private)
{
return true;
}
if (is_null($user_and_memberships))
{
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'],true);
$user_and_memberships[] = $GLOBALS['egw_info']['user']['account_id'];
}
if (!is_array($private)) $private = explode(',',$private);
return (boolean) array_intersect($private,$user_and_memberships);
}
/**
* Change account_id's of private custom-fields
*
* @param string $app
* @param array $ids2change from-id => to-id pairs
* @return int number of changed ids
*/
static function change_account_ids($app, array $ids2change)
{
$changed = 0;
if (($cfs = self::get_customfields($app, true)))
{
foreach($cfs as &$data)
{
if ($data['private'])
{
foreach($data['private'] as &$id)
{
if (isset($ids2change[$id]))
{
$id = $ids2change[$id];
++$changed;
}
}
}
}
if ($changed)
{
self::save_value('customfields', $cfs, $app);
}
}
return $changed;
}
/**
* Return names of custom fields containing account-ids
*
* @param string $app
* @return array account[-commasep] => array of name(s) pairs
*/
static function get_account_cfs($app)
{
$types = array();
if (($cfs = self::get_customfields($app, true)))
{
foreach($cfs as $name => $data)
{
if ($data['type'] == 'select-account' || $data['type'] == 'home-accounts')
{
$types['account'.($data['rows'] > 1 ? '-commasep' : '')][] = $name;
}
}
}
return $types;
//error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use egw_customfields::get() in ". function_backtrace());
return egw_customfields::get($app, $all_private_too, $only_type2);
}
/**
@ -377,6 +286,8 @@ class config
$client_config[$app][$name] = $value;
}
}
// currently not used, therefore no need to add it
//$client_config[$app]['customfields'] = egw_customfields::get($app);
}
// some things need on client-side which are not direct configs
$client_config['phpgwapi']['max_lang_time'] = translation::max_lang_time();
@ -384,6 +295,37 @@ class config
return $client_config;
}
/**
* Unserialize data from either json_encode or PHP serialize
*
* @param string $str serialized prefs
* @return array
*/
protected static function unserialize($str)
{
// handling of new json-encoded arrays
if ($str[0] == '{' && $str[0] != '[')
{
return json_decode($str, true);
}
// handling of not serialized strings
if ($str[0] != 'a' && $str[1] != ':')
{
return $str;
}
// handling of old PHP serialized and addslashed prefs
$data = unserialize($str);
if($data === false)
{
// manually retrieve the string lengths of the serialized array if unserialize failed
$data = unserialize(preg_replace_callback('!s:(\d+):"(.*?)";!s', function($matches)
{
return 's:'.mb_strlen($matches[2],'8bit').':"'.$matches[2].'";';
}, $str));
}
return $data;
}
/**
* Initialise class: reference to db and self::$configs cache
*/
@ -404,17 +346,8 @@ class config
self::$configs = array();
foreach(self::$db->select(config::TABLE,'*',false,__LINE__,__FILE__) as $row)
{
$app = $row['config_app'];
$name = $row['config_name'];
$value = $row['config_value'];
$test = @unserialize($value);
if($test === false)
{
// manually retrieve the string lengths of the serialized array if unserialize failed
$test = @unserialize(preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.mb_strlen('$2','8bit').':\"$2\";'", $value));
}
self::$configs[$app][$name] = is_array($test) ? $test : $value;
self::$configs[$row['config_app']][$row['config_name']] = self::unserialize($row['config_value']);
//error_log(__METHOD__."() configs[$row[config_app]][$row[config_name]]=".array2string(self::$configs[$row['config_app']][$row['config_name']]));
}
egw_cache::setInstance(__CLASS__, 'configs', self::$configs);
}

View File

@ -0,0 +1,293 @@
<?php
/**
* EGroupware API - managing custom-field definitions
*
* @link http://www.egroupware.org
* @author Ralf Becker <rb@stylite.de>
* @copyright 2014 by Ralf Becker <rb@stylite.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @version $Id$
*/
/**
* Managing custom-field definitions
*/
class egw_customfields implements IteratorAggregate
{
/**
* Name of the customfields table
*/
const TABLE = 'egw_customfields';
/**
* Reference to the global db class
*
* @var egw_db
*/
static protected $db;
/**
* app the particular config class is instanciated for
*
* @var string
*/
protected $app;
/**
* should all the private fields be returned too, default no
*
* @var boolean
*/
protected $all_private_too=false;
/**
* Iterator initialised for custom fields
*
* @var ADORecordSet
*/
protected $iterator;
/**
* Constructor
*
* @param string $app
* @param boolean $all_private_too=false should all the private fields be returned too, default no
* @param string $only_type2=null if given only return fields of type2 == $only_type2
* @param int $start=0
* @param int $num_rows=null
* @return array with customfields
*/
function __construct($app, $all_private_too=false, $only_type2=null, $start=0, $num_rows=null)
{
$this->app = $app;
$this->all_private_too = $all_private_too;
$query = array(
'cf_app' => $app,
);
if (!$all_private_too)
{
$memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'], true);
$memberships[] = $GLOBALS['egw_info']['user']['account_id'];
$query[] = $this->commasep_match('cf_private', $memberships);
}
if ($only_type2)
{
$query[] = $this->commasep_match('cf_type2', $only_type2);
}
$this->iterator = self::$db->select(self::TABLE, '*', $query, __LINE__, __FILE__,
!isset($num_rows) ? false : $start, 'ORDER BY cf_order ASC', 'phpgwapi', $num_rows);
}
/**
* Return iterator required for IteratorAggregate
*
* @return egw_db_callback_iterator
*/
function getIterator()
{
return new egw_db_callback_iterator($this->iterator, function($row)
{
$row = egw_db::strip_array_keys($row, 'cf_');
$row['private'] = $row['private'] ? explode(',', $row['private']) : array();
$row['type2'] = $row['type2'] ? explode(',', $row['type2']) : array();
$row['values'] = json_decode($row['values'], true);
$row['needed'] = self::$db->from_bool($row['needed']);
return $row;
}, array(), function($row)
{
return $row['cf_name'];
});
}
/**
* Return SQL to match given values with comma-separated stored column
*
* @param string $column column name "cf_type2" or "cf_private"
* @param string|array $values
*/
protected function commasep_match($column, $values)
{
$to_or = array($column.' IS NULL');
foreach((array) $values as $value)
{
$to_or[] = self::$db->concat('","', $column, '","').' LIKE '.self::$db->quote('%,'.$value.',%');
}
return '('.implode(' OR ', $to_or).')';
}
/**
* Get customfield array of an application
*
* @param string $app
* @param boolean $all_private_too=false should all the private fields be returned too, default no
* @param string $only_type2=null if given only return fields of type2 == $only_type2
* @return array with customfields
*/
public static function get($app, $all_private_too=false, $only_type2=null)
{
$cache_key = $app.':'.(bool)$all_private_too.':'.$only_type2;
$cfs = egw_cache::getInstance(__CLASS__, $cache_key);
if (!isset($cfs))
{
$cfs = iterator_to_array(new egw_customfields($app, $all_private_too, $only_type2));
egw_cache::setInstance(__CLASS__, $cache_key, $cfs);
$cached = egw_cache::getInstance(__CLASS__, $app);
if (!in_array($cache_key, (array)$cached))
{
$cached[] = $cache_key;
egw_cache::setInstance(__CLASS__, $app, $cached);
}
}
//error_log(__METHOD__."('$app', $all_private_too, '$only_type2') returning fields: ".implode(', ', array_keys($cfs)));
return $cfs;
}
/**
* Save a single custom field and invalidate cache
*
* @param array $cf
*/
public static function update(array $cf)
{
self::$db->update(self::TABLE, array(
'cf_label' => $cf['label'],
'cf_type' => $cf['type'],
'cf_type2' => $cf['type2'] ? implode(',', $cf['type2']) : null,
'cf_help' => $cf['help'],
'cf_values' => $cf['values'] ? json_encode($cf['values']) : null,
'cf_len' => (string)$cf['len'] !== '' ? $cf['len'] : null,
'cf_rows' => (string)$cf['rows'] !== '' ? $cf['rows'] : null,
'cf_order' => $cf['order'],
'cf_needed' => $cf['needed'],
'cf_private' => $cf['private'] ? implode(',', $cf['private']) : null,
'cf_modifier' => $GLOBALS['egw_info']['user']['account_id'],
'cf_modified' => time(),
), array(
'cf_name' => $cf['name'],
'cf_app' => $cf['app'],
), __LINE__, __FILE__);
self::invalidate_cache($cf['app']);
}
/**
* Save all custom fields of an app
*
* @param string $app
* @param array $cfs
*/
public static function save($app, array $cfs)
{
$query = array('cf_app' => $app);
if ($cfs) $query[] = self::$db->expression(self::TABLE, 'NOT ', array('cf_name' => array_keys($cfs)));
self::$db->delete(self::TABLE, $query, __LINE__, __FILE__);
foreach($cfs as $name => $cf)
{
if (empty($cf['name'])) $cf['name'] = $name;
if (empty($cf['app'])) $cf['app'] = $app;
self::update($cf);
}
self::invalidate_cache($app);
}
/**
* Invalidate instance cache for all custom fields of given app
*
* @param string $app
*/
protected static function invalidate_cache($app)
{
if (($cached = egw_cache::getInstance(__CLASS__, $app)))
{
foreach($cached as $key)
{
egw_cache::unsetInstance(__CLASS__, $key);
}
egw_cache::unsetInstance(__CLASS__, $app);
}
}
/**
* Change account_id's of private custom-fields
*
* @param string $app
* @param array $ids2change from-id => to-id pairs
* @return integer number of changed ids
*/
public static function change_account_ids($app, array $ids2change)
{
$total = 0;
if (($cfs = self::get_customfields($app, true)))
{
foreach($cfs as &$data)
{
if ($data['private'])
{
$changed = 0;
foreach($data['private'] as &$id)
{
if (isset($ids2change[$id]))
{
$id = $ids2change[$id];
++$changed;
}
}
if ($changed)
{
self::update($data);
$total += $changed;
}
}
}
}
return $total;
}
/**
* Return names of custom fields containing account-ids
*
* @param string $app
* @return array account[-commasep] => array of name(s) pairs
*/
public static function get_account_cfs($app)
{
$types = array();
if (($cfs = self::get_customfields($app, true)))
{
foreach($cfs as $name => $data)
{
if ($data['type'] == 'select-account' || $data['type'] == 'home-accounts')
{
$types['account'.($data['rows'] > 1 ? '-commasep' : '')][] = $name;
}
}
}
return $types;
}
/**
* Initialise our db
*
* We use a reference here (no clone), as we no longer use egw_db::row() or egw_db::next_record()!
*
*/
public static function init_static()
{
if (is_object($GLOBALS['egw']->db))
{
self::$db = $GLOBALS['egw']->db;
}
else
{
self::$db = $GLOBALS['egw_setup']->db;
}
}
}
egw_customfields::init_static();

View File

@ -12,7 +12,7 @@
/* Basic information about this app */
$setup_info['phpgwapi']['name'] = 'phpgwapi';
$setup_info['phpgwapi']['title'] = 'EGroupware API';
$setup_info['phpgwapi']['version'] = '1.9.020';
$setup_info['phpgwapi']['version'] = '1.9.021';
$setup_info['phpgwapi']['versions']['current_header'] = '1.29';
$setup_info['phpgwapi']['enable'] = 3;
$setup_info['phpgwapi']['app_order'] = 1;
@ -50,6 +50,7 @@ $setup_info['phpgwapi']['tables'][] = 'egw_index';
$setup_info['phpgwapi']['tables'][] = 'egw_cat2entry';
$setup_info['phpgwapi']['tables'][] = 'egw_locks';
$setup_info['phpgwapi']['tables'][] = 'egw_sqlfs_props';
$setup_info['phpgwapi']['tables'][] = 'egw_customfields';
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
$setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount';
@ -59,6 +60,12 @@ $setup_info['phpgwapi']['hooks']['addgroup'] = 'phpgwapi.vfs_home_hooks.addGrou
$setup_info['phpgwapi']['hooks']['deletegroup'] = 'phpgwapi.vfs_home_hooks.deleteGroup';
$setup_info['phpgwapi']['hooks']['editgroup'] = 'phpgwapi.vfs_home_hooks.editGroup';
// egw-pear dependency for modified HTTP_WebDAV_Server
$setup_info['phpgwapi']['depends'][] = array(
'appname' => 'egw-pear',
'versions' => Array('1.8','1.9')
);
/* CalDAV/CardDAV/GroupDAV app */
$setup_info['groupdav']['name'] = 'groupdav';
$setup_info['groupdav']['version'] = '1.8';
@ -73,4 +80,3 @@ $setup_info['groupdav']['author'] = $setup_info['groupdav']['maintainer'] = arra
$setup_info['groupdav']['license'] = 'GPL';
$setup_info['groupdav']['hooks']['preferences'] = 'groupdav_hooks::menus';
$setup_info['groupdav']['hooks']['settings'] = 'groupdav_hooks::settings';

View File

@ -458,5 +458,28 @@ $phpgw_baseline = array(
'fk' => array(),
'ix' => array(),
'uc' => array()
),
'egw_customfields' => array(
'fd' => array(
'cf_id' => array('type' => 'auto','nullable' => False),
'cf_app' => array('type' => 'varchar','precision' => '50','nullable' => False,'comment' => 'app-name cf belongs too'),
'cf_name' => array('type' => 'varchar','precision' => '128','nullable' => False,'comment' => 'internal name'),
'cf_label' => array('type' => 'varchar','precision' => '128','comment' => 'label to display'),
'cf_type' => array('type' => 'varchar','precision' => '64','nullable' => False,'default' => 'text','comment' => 'type of field'),
'cf_type2' => array('type' => 'varchar','precision' => '2048','comment' => 'comma-separated subtypes of app, cf is valid for'),
'cf_help' => array('type' => 'varchar','precision' => '256','comment' => 'helptext'),
'cf_values' => array('type' => 'varchar','precision' => '8096','comment' => 'json object with value label pairs'),
'cf_len' => array('type' => 'int','precision' => '2','comment' => 'length or columns of field'),
'cf_rows' => array('type' => 'int','precision' => '2','comment' => 'rows of field'),
'cf_order' => array('type' => 'int','precision' => '2','comment' => 'order to display fields'),
'cf_needed' => array('type' => 'bool','default' => '0','comment' => 'field is required'),
'cf_private' => array('type' => 'varchar','meta' => 'account-commasep','precision' => '2048','comment' => 'comma-separated account_id'),
'cf_modifier' => array('type' => 'int','meta' => 'account','precision' => '4','comment' => 'last modifier'),
'cf_modified' => array('type' => 'timestamp','default' => 'current_timestamp','comment' => 'last modification time')
),
'pk' => array('cf_id'),
'fk' => array(),
'ix' => array(array('cf_app', 'cf_order')),
'uc' => array(array('cf_app', 'cf_name'))
)
);

View File

@ -491,3 +491,70 @@ function phpgwapi_upgrade1_9_019()
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.020';
}
/**
* Create own table for custom-fields and migrate values over from egw_config
*
* @return string
*/
function phpgwapi_upgrade1_9_020()
{
$GLOBALS['egw_setup']->oProc->CreateTable('egw_customfields',array(
'fd' => array(
'cf_id' => array('type' => 'auto','nullable' => False),
'cf_app' => array('type' => 'varchar','precision' => '50','nullable' => False,'comment' => 'app-name cf belongs too'),
'cf_name' => array('type' => 'varchar','precision' => '128','nullable' => False,'comment' => 'internal name'),
'cf_label' => array('type' => 'varchar','precision' => '128','comment' => 'label to display'),
'cf_type' => array('type' => 'varchar','precision' => '64','nullable' => False,'default' => 'text','comment' => 'type of field'),
'cf_type2' => array('type' => 'varchar','precision' => '2048','comment' => 'comma-separated subtypes of app, cf is valid for'),
'cf_help' => array('type' => 'varchar','precision' => '256','comment' => 'helptext'),
'cf_values' => array('type' => 'varchar','precision' => '8096','comment' => 'json object with value label pairs'),
'cf_len' => array('type' => 'int','precision' => '2','comment' => 'length or columns of field'),
'cf_rows' => array('type' => 'int','precision' => '2','comment' => 'rows of field'),
'cf_order' => array('type' => 'int','precision' => '2','comment' => 'order to display fields'),
'cf_needed' => array('type' => 'bool','default' => '0','comment' => 'field is required'),
'cf_private' => array('type' => 'varchar','meta' => 'account-commasep','precision' => '2048','comment' => 'comma-separated account_id'),
'cf_modifier' => array('type' => 'int','meta' => 'account','precision' => '4','comment' => 'last modifier'),
'cf_modified' => array('type' => 'timestamp','default' => 'current_timestamp','comment' => 'last modification time')
),
'pk' => array('cf_id'),
'fk' => array(),
'ix' => array(array('cf_app', 'cf_order')),
'uc' => array(array('cf_app', 'cf_name'))
));
foreach($GLOBALS['egw_setup']->db->select('egw_config', '*', "config_name='customfields'", __LINE__, __FILE__) as $row)
{
$cfs = $row['config_value'][1] == ':' ? unserialize($row['config_value']) : json_decode($row['config_value']);
foreach($cfs as $name => $cf)
{
$data = array(
'cf_name' => $name,
'cf_app' => $row['config_app'],
);
foreach($cf as $attr => $val)
{
switch($attr)
{
case 'private':
case 'type2':
$val = $val ? implode(',', $val) : null;
break;
case 'values':
$val = $val && is_array($val) ? json_encode($val) : null;
break;
case 'len':
case 'rows':
$val = (string)$val !== '' ? $val : null;
break;
}
$data['cf_'.$attr] = $val;
}
$GLOBALS['egw_setup']->db->insert('egw_customfields', $data, false, __LINE__, __FILE__);
}
}
$GLOBALS['egw_setup']->db->delete('egw_config', "config_name='customfields'", __LINE__, __FILE__);
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.021';
}