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'; +} +