Index: branches/5.3.x/core/units/helpers/col_picker_helper.php =================================================================== diff -u -N -r15698 -r15943 --- branches/5.3.x/core/units/helpers/col_picker_helper.php (.../col_picker_helper.php) (revision 15698) +++ branches/5.3.x/core/units/helpers/col_picker_helper.php (.../col_picker_helper.php) (revision 15943) @@ -1,6 +1,6 @@ UseFreezer = $this->Application->ConfigValue('UseColumnFreezer'); + $splitted = $this->Application->processPrefix($prefix); + $this->Init($splitted['prefix'], $splitted['special']); + + $this->useFreezer = $this->Application->ConfigValue('UseColumnFreezer'); + + $this->gridName = $grid_name; + $this->pickerData = $this->loadColumns(); } - function LoadColumns($prefix) + /** + * Loads picker data. + * + * @return ColumnSet + */ + protected function loadColumns() { $default_value = $this->Application->isAdmin ? ALLOW_DEFAULT_SETTINGS : false; - $val = $this->Application->RecallPersistentVar($this->_getVarName($prefix, 'get'), $default_value); + $value = $this->Application->RecallPersistentVar($this->getVarName('get'), $default_value); - if (!$val) { - $cols = $this->RebuildColumns($prefix); + if ( !$value ) { + $columns = $this->rebuildColumns(); } else { - $cols = unserialize($val); - $current_cols = $this->GetColumns($prefix); + $default_columns = $this->getDefaultColumns(); + $columns = new ColumnSet(unserialize($value)); - if ($cols === false || $cols['crc'] != $current_cols['crc']) - { - $cols = $this->RebuildColumns($prefix, $cols); + if ( !$columns->same($default_columns) ) { + $columns = $this->rebuildColumns($columns); } } - return $cols; - } - function PreparePicker($prefix, $grid_name) - { - $this->SetGridName($grid_name); - $this->PickerData = $this->LoadColumns($prefix); + return $columns; } - function ApplyPicker($prefix, &$fields, $grid_name) + /** + * Merges default column set with given one. + * + * @param ColumnSet $current_columns Currently used column set. + * + * @return ColumnSet + */ + protected function rebuildColumns(ColumnSet $current_columns = null) { - $this->PreparePicker($prefix, $grid_name); - uksort($fields, array($this, 'CmpElems')); - $this->RemoveHiddenColumns($fields); - } - - function SetGridName($grid_name) - { - $this->GridName = $grid_name; - } - - function CmpElems($a, $b) - { - // remove language prefix from field, because formatter renamed column - if (in_array($a, $this->formatterRenamed)) { - $a = preg_replace('/^l[\d]+_/', '', $a); + if ( isset($current_columns) ) { + $columns = $current_columns->merge($this->getDefaultColumns(), self::DEFAULT_COLUMN_WIDTH); } - - if (in_array($b, $this->formatterRenamed)) { - $b = preg_replace('/^l[\d]+_/', '', $b); + else { + $columns = $this->getDefaultColumns(); } - $a_index = array_search($a, $this->PickerData['order']); - $b_index = array_search($b, $this->PickerData['order']); + $this->storeCols($columns); - if ($a_index == $b_index) { - return 0; - } - - return ($a_index < $b_index) ? -1 : 1; + return $columns; } - function RebuildColumns($prefix, $current=null) + /** + * Returns column set built purely from grid definition in unit config. + * + * @return ColumnSet + */ + protected function getDefaultColumns() { - // get default columns from unit config - $cols = $this->GetColumns($prefix); + $grid_columns = $this->getColumnsFromUnitConfig(); - if (is_array($current)) { - // 1. prepare visible columns + // we NEED to recall dummy here to apply field changes imposed by formatters, + // such as replacing multilingual field titles etc. + $this->Application->recallObject($this->getPrefixSpecial(), null, array('skip_autoload' => 1)); - // keep user column order (common columns between user and default grid) - $common = array_intersect($current['order'], $cols['order']); + $counter = 0; + $fields = $titles = $widths = $hidden = array(); - // get new columns (found in default grid, but not found in user's grid) - $added = array_diff($cols['order'], $current['order']); - - if (in_array('__FREEZER__', $added)) { - // in case if freezer was added, then make it first column - array_unshift($common, '__FREEZER__'); - unset($added[array_search('__FREEZER__', $added)]); + foreach ( $grid_columns as $name => $options ) { + if ( array_key_exists('formatter_renamed', $options) && $options['formatter_renamed'] ) { + // remove language prefix from field, because formatter renamed column + $this->formatterRenamed[] = $name; + $name = preg_replace('/^l[\d]+_/', '', $name); } - $cols['order'] = array_merge($common, $added); + $fields[$counter] = $name; + $titles[$name] = isset($options['title']) ? $options['title'] : 'column:la_fld_' . $name; + $widths[$name] = isset($options['width']) ? $options['width'] : self::DEFAULT_COLUMN_WIDTH; - // 2. prepare hidden columns - if ($added) { - $hidden_added = array_intersect($added, $cols['hidden_fields']); - $cols['hidden_fields'] = array_intersect($current['order'], $current['hidden_fields']); - - // when some of new columns are hidden, then keep them hidden - foreach ($hidden_added as $position => $field) { - $cols['hidden_fields'][$position] = $field; - } + if ( isset($options['hidden']) && $options['hidden'] ) { + $hidden[$counter] = $name; } - else { - $cols['hidden_fields'] = array_intersect($current['order'], $current['hidden_fields']); - } - foreach($common as $col) { - $cols['widths'][$col] = isset($current['widths'][$col]) ? $current['widths'][$col] : $this->defaultColumnWidth; - } - $this->SetCRC($cols); + $counter++; } - $this->StoreCols($prefix, $cols); - return $cols; + $cols = array( + 'order' => $fields, + 'titles' => $titles, + 'hidden_fields' => $hidden, + 'widths' => $widths, + ); + + return new ColumnSet($cols); } - function StoreCols($prefix, $cols) + /** + * Returns columns as-is from unit config. + * + * @return array + */ + protected function getColumnsFromUnitConfig() { - $this->Application->StorePersistentVar($this->_getVarName($prefix, 'set'), serialize($cols)); + $grid = $this->getUnitConfig()->getGridByName($this->gridName); + + if ( $this->useFreezer ) { + $freezer_column = array('__FREEZER__' => array('title' => '__FREEZER__')); + + return array_merge_recursive($freezer_column, $grid['Fields']); + } + + return $grid['Fields']; } /** * Gets variable name in persistent session to store column positions in * - * @param string $prefix * @param string $mode * @return string */ - function _getVarName($prefix, $mode = 'get') + protected function getVarName($mode = 'get') { - $view_name = $this->Application->RecallVar($prefix . '_current_view'); + $view_name = $this->Application->RecallVar($this->Prefix . '_current_view'); - $ret = $prefix . '[' . $this->GridName . ']columns_.' . $view_name; - if ($mode == 'get') { - if ($this->Application->RecallPersistentVar($ret) === false) { - $ret = $prefix . '_columns_.' . $view_name; + $ret = $this->Prefix . '[' . $this->gridName . ']columns_.' . $view_name; + + if ( $mode == 'get' ) { + // fallback to old storage system, that remember only 1 grid configuration per-unit + if ( $this->Application->RecallPersistentVar($ret) === false ) { + $ret = $this->Prefix . '_columns_.' . $view_name; } } return $ret; } - function GetColumns($prefix) + /** + * Returns picker data. + * + * @return ColumnSet + */ + public function getData() { - $splited = $this->Application->processPrefix($prefix); - $grid = $this->Application->getUnitConfig($splited['prefix'])->getGridByName($this->GridName); + return $this->pickerData; + } - if ( $this->UseFreezer ) { - $freezer_column = Array ('__FREEZER__' => Array ('title' => '__FREEZER__')); - $conf_fields = array_merge_recursive($freezer_column, $grid['Fields']); - } - else { - $conf_fields = $grid['Fields']; - } - - // we NEED to recall dummy here to apply fields changes imposed by formatters, - // such as replacing multilingual field titles etc. - $dummy = $this->Application->recallObject($prefix, null, Array ('skip_autoload' => 1)); - - $counter = 0; - $hidden = array(); - $fields = array(); - $titles = array(); - $widths = array(); - foreach ($conf_fields as $name => $options) { - if (array_key_exists('formatter_renamed', $options) && $options['formatter_renamed']) { - // remove language prefix from field, because formatter renamed column - $this->formatterRenamed[] = $name; - $name = preg_replace('/^l[\d]+_/', '', $name); - } - - $fields[$counter] = $name; - $titles[$name] = isset($options['title']) ? $options['title'] : 'column:la_fld_' . $name; - $widths[$name] = isset($options['width']) ? $options['width'] : $this->defaultColumnWidth; // only once per grid ! - - if (isset($options['hidden']) && $options['hidden']) { - $hidden[$counter] = $name; - } - - $counter++; - } - $sorted_fields = $fields; - sort($sorted_fields); - $cols = array( - 'order' => $fields, - 'titles' => $titles, - 'hidden_fields' => $hidden, - 'widths' => $widths, - ); - $this->SetCRC($cols); - return $cols; + protected function storeCols(ColumnSet $cols) + { + $this->Application->StorePersistentVar($this->getVarName('set'), serialize($cols->toArray())); } - function SetCRC(&$cols) + /** + * Reorders given grid configuration based on picker data and removes hidden columns. + * + * @param array $grid_columns + * + * @return array + */ + public function apply(array $grid_columns) { - $sorted_fields = $cols['order']; - $sorted_titles = $cols['titles']; - asort($sorted_fields); - asort($sorted_titles); - $cols['crc'] = crc32(implode(',', $sorted_fields).implode(',', $sorted_titles)); + uksort($grid_columns, array($this, 'compareColumns')); + + return $this->removeHidden($grid_columns); } - function RemoveHiddenColumns(&$fields) + /** + * Removes columns, that are hidden in picker configuration. + * + * @param array $grid_columns Grid columns. + * + * @return array + */ + protected function removeHidden(array $grid_columns) { $to_remove = array(); - foreach ($fields as $name => $options) { - if (array_key_exists('formatter_renamed', $options) && $options['formatter_renamed']) { + + foreach ( $grid_columns as $name => $options ) { + if ( array_key_exists('formatter_renamed', $options) && $options['formatter_renamed'] ) { // remove language prefix from field, because formatter renamed column $name_renamed = preg_replace('/^l[\d]+_/', '', $name); } else { $name_renamed = $name; } - if (array_search($name_renamed, $this->PickerData['hidden_fields']) !== false) { + if ( $this->pickerData->isHidden($name_renamed) ) { $to_remove[] = $name; } } - foreach ($to_remove as $name) { - unset($fields[$name]); + foreach ( $to_remove as $name ) { + unset($grid_columns[$name]); } + + return $grid_columns; } - function SaveColumns($prefix, $picked, $hidden) + /** + * Helper function for reordering grid columns. + * + * @param string $first_column + * @param string $second_column + * + * @return integer + */ + protected function compareColumns($first_column, $second_column) { + $first_column_order = $this->pickerData->getOrder($this->fixColumnName($first_column)); + $second_column_order = $this->pickerData->getOrder($this->fixColumnName($second_column)); + + if ( $first_column_order == $second_column_order ) { + return 0; + } + + return ($first_column_order < $second_column_order) ? -1 : 1; + } + + /** + * Saves changes to column widths. + * + * @param string $picked Visible columns. + * @param string $hidden Hidden columns. + * + * @return void + */ + public function saveColumns($picked, $hidden) + { $order = $picked ? explode('|', $picked) : array(); $hidden = $hidden ? explode('|', $hidden) : array(); $order = array_merge($order, $hidden); - $cols = $this->LoadColumns($prefix); - $cols['order'] = $order; - $cols['hidden_fields'] = $hidden; + $this->pickerData->allFields = $order; + $this->pickerData->hiddenFields = $hidden; - $this->SetCRC($cols); - $this->StoreCols($prefix, $cols); + $this->storeCols($this->pickerData); } - function SaveWidths($prefix, $widths) + /** + * Saves changes to column widths. + * + * @param array|string $widths Column width info. + * + * @return void + */ + public function saveWidths($widths) { - if (!is_array($widths)) { + if ( !is_array($widths) ) { $widths = explode(':', $widths); } $i = 0; array_shift($widths); // removing first col (checkbox col) width - foreach ($this->PickerData['order'] as $ord => $field) { - if ($field == '__FREEZER__') { + foreach ( $this->pickerData->allFields as $field ) { + if ( $field == '__FREEZER__' ) { continue; } - $this->PickerData['widths'][$field] = isset($widths[$i]) ? $widths[$i] : $this->defaultColumnWidth; + $this->pickerData->widths[$field] = isset($widths[$i]) ? $widths[$i] : self::DEFAULT_COLUMN_WIDTH; $i++; } - $this->StoreCols($prefix, $this->PickerData); + $this->storeCols($this->pickerData); } - function GetWidth($field) + /** + * Returns width of a given column. + * + * @param string $column_name Column name. + * + * @return string + */ + public function getWidth($column_name) { - if (in_array($field, $this->formatterRenamed)) { + return $this->pickerData->getWidth($this->fixColumnName($column_name)); + } + + /** + * Removes language prefix from formatter renamed column. + * + * @param string $name Column name. + * + * @return string + */ + protected function fixColumnName($name) + { + if ( in_array($name, $this->formatterRenamed) ) { // remove language prefix from field, because formatter renamed column - $field = preg_replace('/^l[\d]+_/', '', $field); + $column_name = preg_replace('/^l[\d]+_/', '', $name); } - return isset($this->PickerData['widths'][$field]) ? $this->PickerData['widths'][$field] : false; + return $name; } + +} + + +class ColumnSet extends kBase +{ + + /** + * List of all fields (key - order, value - field name). + * + * @var array + */ + public $allFields; + + /** + * List of hidden fields (key - order, value - field name). + * + * @var array + */ + public $hiddenFields; + + /** + * List of field titles (key - field name, value - label). + * + * @var array + */ + public $titles; + + /** + * List of field widths (key - field name, value - width). + * + * @var array + */ + public $widths; + + /** + * Creates column set. + * + * @param array $data Data. + */ + public function __construct(array $data) + { + $this->allFields = $data['order']; + $this->hiddenFields = $data['hidden_fields']; + + $this->titles = $data['titles']; + $this->widths = $data['widths']; + } + + /** + * Returns array representation of an object. + * + * @return array + */ + public function toArray() + { + $ret = array( + 'order' => $this->allFields, + 'hidden_fields' => $this->hiddenFields, + + 'titles' => $this->titles, + 'widths' => $this->widths, + ); + + return $ret; + } + + /** + * Returns title for a column. + * + * @param string $column_name Column name. + * + * @return string + */ + public function getTitle($column_name) + { + return $this->titles[$column_name]; + } + + /** + * Returns width of a column. + * + * @param string $column_name Column name. + * @param mixed $default Default value. + * + * @return string + */ + public function getWidth($column_name, $default = false) + { + return isset($this->widths[$column_name]) ? $this->widths[$column_name] : $default; + } + + /** + * Returns order for a column. + * + * @param string $column_name Column name. + * + * @return integer|boolean + */ + public function getOrder($column_name) + { + return array_search($column_name, $this->allFields); + } + + /** + * Determines if a column is hidden. + * + * @param string $column_name Column name. + * + * @return boolean + */ + public function isHidden($column_name) + { + return array_search($column_name, $this->hiddenFields) !== false; + } + + /** + * Returns checksum for current column set. + * + * @return integer + */ + public function getChecksum() + { + $sorted_fields = $this->allFields; + $sorted_titles = $this->titles; + asort($sorted_fields); + asort($sorted_titles); + + return crc32(implode(',', $sorted_fields) . implode(',', $sorted_titles)); + } + + /** + * Compares 2 column sets. + * + * @param ColumnSet $columns Column set. + * + * @return boolean + */ + public function same(ColumnSet $columns) + { + return $this->getChecksum() == $columns->getChecksum(); + } + + /** + * Merges current column set with given one. + * + * @param ColumnSet $default_columns Column set to merge with. + * @param integer $default_width Default column width. + * + * @return self + */ + public function merge(ColumnSet $default_columns, $default_width) + { + // keep user column order (common columns between user's and default grid) + $common = array_intersect($this->allFields, $default_columns->allFields); + + // get new columns (found in default grid, but not found in user's grid) + $added = array_diff($default_columns->allFields, $this->allFields); + + // in case if freezer was added, then make it first column + if ( in_array('__FREEZER__', $added) ) { + array_unshift($common, '__FREEZER__'); + unset($added[array_search('__FREEZER__', $added)]); + } + + // keep added column position + $this->allFields = $common; + + foreach ( $added as $added_column ) { + $this->insertAfter($added_column, $default_columns->getPrecedingColumn($added_column)); + } + + $this->titles = $default_columns->titles; + $this->hiddenFields = array_intersect($this->allFields, $this->hiddenFields); + + // update width & hidden status for added columns + foreach ( $added as $added_column ) { + $this->widths[$added_column] = $default_columns->getWidth($added_column, $default_width); + + if ( $default_columns->isHidden($added_column) ) { + $this->hiddenFields[$default_columns->getOrder($added_column)] = $added_column; + } + } + + return $this; + } + + /** + * Inserts one column after another. + * + * @param string $new_column Name of column to insert. + * @param string $after_column Name of column to insert after. + * + * @return self + */ + public function insertAfter($new_column, $after_column) + { + $addition = array($after_column, $new_column); + array_splice($this->allFields, $this->getOrder($after_column), 1, $addition); + + return $this; + } + + /** + * Returns preceding column. + * + * @param string $name Column name. + * + * @return string + */ + public function getPrecedingColumn($name) + { + $prev_column = reset($this->allFields); + + foreach ( $this->allFields as $column ) { + if ( $column == $name ) { + return $prev_column; + } + + $prev_column = $column; + } + + return ''; + } + } \ No newline at end of file Index: branches/5.3.x/core/kernel/db/db_tag_processor.php =================================================================== diff -u -N -r15928 -r15943 --- branches/5.3.x/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 15928) +++ branches/5.3.x/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 15943) @@ -1,6 +1,6 @@ getUnitConfig()->getGridByName($params['grid']); $grid_config = $grid['Fields']; - $picker_helper = $this->Application->recallObject('ColumnPickerHelper'); - /* @var $picker_helper kColumnPickerHelper */ + $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); + $grid_config = $picker_helper->apply($grid_config); - $picker_helper->ApplyPicker($this->getPrefixSpecial(), $grid_config, $params['grid']); - if ( $mode == 'fields' ) { return "'" . join("','", array_keys($grid_config)) . "'"; } @@ -247,7 +245,7 @@ $block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field; $block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field; - $w = $picker_helper->GetWidth($field); + $w = $picker_helper->getWidth($field); if ( $w ) { // column picker width overrides width from unit config @@ -269,21 +267,19 @@ function PickerCRC($params) { - /* @var $picker_helper kColumnPickerHelper */ - $picker_helper = $this->Application->recallObject('ColumnPickerHelper'); - $picker_helper->SetGridName($params['grid']); - $data = $picker_helper->LoadColumns($this->getPrefixSpecial()); - return $data['crc']; + $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); + + return $picker_helper->getData()->getChecksum(); } function FreezerPosition($params) { - /* @var $picker_helper kColumnPickerHelper */ - $picker_helper = $this->Application->recallObject('ColumnPickerHelper'); - $picker_helper->SetGridName($params['grid']); - $data = $picker_helper->LoadColumns($this->getPrefixSpecial()); - $freezer_pos = array_search('__FREEZER__', $data['order']); - return $freezer_pos === false || in_array('__FREEZER__', $data['hidden_fields']) ? 1 : ++$freezer_pos; + $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); + $data = $picker_helper->getData(); + + $freezer_pos = $data->getOrder('__FREEZER__'); + + return $freezer_pos === false || $data->isHidden('__FREEZER__') ? 1 : ++$freezer_pos; } function GridFieldsCount($params) Index: branches/5.3.x/core/units/admin/admin_tag_processor.php =================================================================== diff -u -N -r15928 -r15943 --- branches/5.3.x/core/units/admin/admin_tag_processor.php (.../admin_tag_processor.php) (revision 15928) +++ branches/5.3.x/core/units/admin/admin_tag_processor.php (.../admin_tag_processor.php) (revision 15943) @@ -1,6 +1,6 @@ Application->recallObject('ColumnPickerHelper'); - $picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name')); + $picker_helper = new kColumnPickerHelper( + $this->Application->RecallVar('main_prefix'), + $this->Application->GetLinkedVar('grid_name') + ); - $main_prefix = $this->Application->RecallVar('main_prefix'); - $cols = $picker_helper->LoadColumns($main_prefix); + $cols = $picker_helper->getData(); $this->Application->Phrases->AddCachedPhrase('__FREEZER__', '-------------'); $o = ''; - if (isset($params['hidden']) && $params['hidden']) { - foreach ($cols['hidden_fields'] as $col) { - $title = $this->Application->Phrase($cols['titles'][$col]); - $o .= "