Application->processPrefix($prefix); $this->Init($splitted['prefix'], $splitted['special']); $this->useFreezer = $this->Application->ConfigValue('UseColumnFreezer'); $this->gridName = $grid_name; $this->pickerData = $this->loadColumns(); } /** * Loads picker data. * * @return ColumnSet */ protected function loadColumns() { $default_value = $this->Application->isAdmin ? ALLOW_DEFAULT_SETTINGS : false; $value = $this->Application->RecallPersistentVar($this->getVarName('get'), $default_value); if ( !$value ) { $columns = $this->rebuildColumns(); } else { $default_columns = $this->getDefaultColumns(); $columns = new ColumnSet(unserialize($value)); if ( !$columns->same($default_columns) ) { $columns = $this->rebuildColumns($columns); } } return $columns; } /** * Merges default column set with given one. * * @param ColumnSet $current_columns Currently used column set. * * @return ColumnSet */ protected function rebuildColumns(ColumnSet $current_columns = null) { if ( isset($current_columns) ) { $columns = $current_columns->merge($this->getDefaultColumns(), self::DEFAULT_COLUMN_WIDTH); } else { $columns = $this->getDefaultColumns(); } $this->storeCols($columns); return $columns; } /** * Returns column set built purely from grid definition in unit config. * * @return ColumnSet */ protected function getDefaultColumns() { $grid_columns = $this->getColumnsFromUnitConfig(); // 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)); $counter = 0; $fields = $titles = $widths = $hidden = array(); 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); } $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; if ( isset($options['hidden']) && $options['hidden'] ) { $hidden[$counter] = $name; } $counter++; } $cols = array( 'order' => $fields, 'titles' => $titles, 'hidden_fields' => $hidden, 'widths' => $widths, ); return new ColumnSet($cols); } /** * Returns columns as-is from unit config. * * @return array */ protected function getColumnsFromUnitConfig() { $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 $mode * @return string */ protected function getVarName($mode = 'get') { $view_name = $this->Application->RecallVar($this->Prefix . '_current_view'); $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; } /** * Returns picker data. * * @return ColumnSet */ public function getData() { return $this->pickerData; } protected function storeCols(ColumnSet $cols) { $this->Application->StorePersistentVar($this->getVarName('set'), serialize($cols->toArray())); } /** * Reorders given grid configuration based on picker data and removes hidden columns. * * @param array $grid_columns * * @return array */ public function apply(array $grid_columns) { uksort($grid_columns, array($this, 'compareColumns')); return $this->removeHidden($grid_columns); } /** * 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 ( $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 ( $this->pickerData->isHidden($name_renamed) ) { $to_remove[] = $name; } } foreach ( $to_remove as $name ) { unset($grid_columns[$name]); } return $grid_columns; } /** * 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); $this->pickerData->allFields = $order; $this->pickerData->hiddenFields = $hidden; $this->storeCols($this->pickerData); } /** * Saves changes to column widths. * * @param array|string $widths Column width info. * * @return void */ public function saveWidths($widths) { if ( !is_array($widths) ) { $widths = explode(':', $widths); } $i = 0; array_shift($widths); // removing first col (checkbox col) width foreach ( $this->pickerData->allFields as $field ) { if ( $field == '__FREEZER__' || $this->pickerData->isHidden($field) ) { continue; } $this->pickerData->widths[$field] = isset($widths[$i]) ? $widths[$i] : self::DEFAULT_COLUMN_WIDTH; $i++; } $this->storeCols($this->pickerData); } /** * Returns width of a given column. * * @param string $column_name Column name. * * @return string */ public function getWidth($column_name) { 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. $name = preg_replace('/^l[\d]+_/', '', $name); } 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 ''; } }