diff --git a/admin/inc/class.admin_cmd_change_account_id.inc.php b/admin/inc/class.admin_cmd_change_account_id.inc.php
index 9438e8f54d..f78a9bd942 100644
--- a/admin/inc/class.admin_cmd_change_account_id.inc.php
+++ b/admin/inc/class.admin_cmd_change_account_id.inc.php
@@ -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";
}
}
diff --git a/admin/inc/class.customfields.inc.php b/admin/inc/class.customfields.inc.php
index b4ee856abd..d9c44cf105 100644
--- a/admin/inc/class.customfields.inc.php
+++ b/admin/inc/class.customfields.inc.php
@@ -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 '
uicustomfields::save_repository() \$this->fields=
'; print_r($this->fields); echo "
\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);
}
/**
diff --git a/etemplate/inc/class.customfields_widget.inc.php b/etemplate/inc/class.customfields_widget.inc.php
index 64b5018af5..4209051dab 100644
--- a/etemplate/inc/class.customfields_widget.inc.php
+++ b/etemplate/inc/class.customfields_widget.inc.php
@@ -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;
diff --git a/etemplate/inc/class.etemplate_widget_customfields.inc.php b/etemplate/inc/class.etemplate_widget_customfields.inc.php
index fc8707a8c8..976ec5c819 100644
--- a/etemplate/inc/class.etemplate_widget_customfields.inc.php
+++ b/etemplate/inc/class.etemplate_widget_customfields.inc.php
@@ -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
diff --git a/etemplate/inc/class.so_sql_cf.inc.php b/etemplate/inc/class.so_sql_cf.inc.php
index 919330d309..7c70802147 100644
--- a/etemplate/inc/class.so_sql_cf.inc.php
+++ b/etemplate/inc/class.so_sql_cf.inc.php
@@ -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);
}
/**
diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php
index 347a061e98..1336948d7a 100644
--- a/infolog/inc/class.infolog_bo.inc.php
+++ b/infolog/inc/class.infolog_bo.inc.php
@@ -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']);
diff --git a/infolog/inc/class.infolog_customfields.inc.php b/infolog/inc/class.infolog_customfields.inc.php
index 23fd88bc10..1db61e4e66 100644
--- a/infolog/inc/class.infolog_customfields.inc.php
+++ b/infolog/inc/class.infolog_customfields.inc.php
@@ -368,7 +368,7 @@ class infolog_customfields
//echo ''.__METHOD__.'() \$this->status=
'; print_r($this->status); echo "
\n";
config::save_value('status',$this->status,'infolog');
//echo ''.__METHOD__.'() \$this->fields=
'; print_r($this->fields); echo "
\n";
- config::save_value('customfields',$this->fields,'infolog');
+ egw_customfields::save('infolog', $this->fields);
config::save_value('group_owners',$this->group_owners,'infolog');
}
}
diff --git a/phpgwapi/inc/class.config.inc.php b/phpgwapi/inc/class.config.inc.php
index 2286429262..5b5c648403 100755
--- a/phpgwapi/inc/class.config.inc.php
+++ b/phpgwapi/inc/class.config.inc.php
@@ -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);
}
diff --git a/phpgwapi/inc/class.egw_customfields.inc.php b/phpgwapi/inc/class.egw_customfields.inc.php
new file mode 100755
index 0000000000..ca10ae2b43
--- /dev/null
+++ b/phpgwapi/inc/class.egw_customfields.inc.php
@@ -0,0 +1,293 @@
+
+ * @copyright 2014 by Ralf Becker
+ * @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();
diff --git a/phpgwapi/setup/setup.inc.php b/phpgwapi/setup/setup.inc.php
index 8017957a16..ab235ef2ff 100755
--- a/phpgwapi/setup/setup.inc.php
+++ b/phpgwapi/setup/setup.inc.php
@@ -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';
-
diff --git a/phpgwapi/setup/tables_current.inc.php b/phpgwapi/setup/tables_current.inc.php
index 0160eb1bdc..67238c12f5 100644
--- a/phpgwapi/setup/tables_current.inc.php
+++ b/phpgwapi/setup/tables_current.inc.php
@@ -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'))
)
);
diff --git a/phpgwapi/setup/tables_update.inc.php b/phpgwapi/setup/tables_update.inc.php
index d6fdd43a2b..cbbc7ea4b4 100644
--- a/phpgwapi/setup/tables_update.inc.php
+++ b/phpgwapi/setup/tables_update.inc.php
@@ -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';
+}
+