<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace qbank_columnsortorder;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/questionlib.php');
use context_system;
> use core_question\local\bank\column_base;
use core_question\local\bank\question_edit_contexts;
> use core_question\local\bank\column_manager_base;
use core_question\local\bank\view;
> use qbank_columnsortorder\local\bank\column_action_move;
use moodle_url;
> use qbank_columnsortorder\local\bank\column_action_remove;
> use qbank_columnsortorder\local\bank\column_action_resize;
/**
> use qbank_columnsortorder\local\bank\preview_view;
* Class column_manager responsible for loading and saving order to the config setting.
*
* @package qbank_columnsortorder
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @author Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
< class column_manager {
> class column_manager extends column_manager_base {
/**
< * @var array|bool Column order as set in config_plugins 'class' => 'position', ie: question_type_column => 3.
> * @var array Column order as set in config_plugins 'class' => 'position', ie: question_type_column => 3.
*/
public $columnorder;
/**
< * @var array|bool Disabled columns in config_plugins table.
> * @var array hidden columns.
> */
> public $hiddencolumns;
>
> /**
> * @var array columns with size.
> */
> public $colsize;
>
> /**
> * @var array Disabled columns in config_plugins table.
*/
public $disabledcolumns;
/**
* Constructor for column_manager class.
*
> * @param bool $globalsettings Only use the global default settings, ignoring user preferences?
*/
< public function __construct() {
< $this->columnorder = get_config('qbank_columnsortorder', 'enabledcol');
< $this->disabledcolumns = get_config('qbank_columnsortorder', 'disabledcol');
> public function __construct(bool $globalsettings = false) {
> $this->columnorder = $this->setup_property('enabledcol', $globalsettings);
> if (empty($this->columnorder)) {
> $this->columnorder = [
> 'core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column',
> 'qbank_viewquestiontype\question_type_column' . column_base::ID_SEPARATOR . 'question_type_column',
> 'qbank_viewquestionname\question_name_idnumber_tags_column' . column_base::ID_SEPARATOR .
> 'question_name_idnumber_tags_column',
> 'core_question\local\bank\edit_menu_column' . column_base::ID_SEPARATOR . 'edit_menu_column',
> 'qbank_editquestion\question_status_column' . column_base::ID_SEPARATOR . 'question_status_column',
> 'qbank_history\version_number_column' . column_base::ID_SEPARATOR . 'version_number_column',
> 'qbank_viewcreator\creator_name_column' . column_base::ID_SEPARATOR . 'creator_name_column',
> 'qbank_comment\comment_count_column' . column_base::ID_SEPARATOR . 'comment_count_column',
> ];
> }
> $this->hiddencolumns = $this->setup_property('hiddencols', $globalsettings);
> $this->colsize = $this->setup_property('colsize', $globalsettings, 'json');
> $this->disabledcolumns = $this->setup_property('disabledcol', true); // No user preference for disabledcol.
>
if ($this->columnorder) {
< $this->columnorder = array_flip(explode(',', $this->columnorder));
> $this->columnorder = array_flip($this->columnorder);
}
if ($this->disabledcolumns) {
< $this->disabledcolumns = array_flip(explode(',', $this->disabledcolumns));
> $this->disabledcolumns = array_flip($this->disabledcolumns);
> }
> }
>
> /**
> * Return the value for the given property, based the saved user preference or config setting.
> *
> * If no value is currently stored, returns an empty array.
> *
> * @param string $setting The identifier used for the saved config and user preference settings.
> * @param bool $global Only get the global default, ignoring the user preference?
> * @param string $encoding The encoding used to store the property - csv or json
> * @return array
> */
> private function setup_property(string $setting, bool $global = false, $encoding = 'csv'): array {
> $value = get_config('qbank_columnsortorder', $setting);
> if (!$global) {
> $value = get_user_preferences("qbank_columnsortorder_{$setting}", $value);
> }
> if (empty($value)) {
> return [];
}
> return $encoding == 'csv' ? explode(',', $value) : json_decode($value);
}
/**
* Sets column order in the qbank_columnsortorder plugin config.
*
< * @param array $columns Column order to set.
> * @param ?array $columns Column order to set. Null value clears the setting.
> * @param bool $global save this as a global default, rather than a user preference?
*/
< public static function set_column_order(array $columns) : void {
> public static function set_column_order(?array $columns, bool $global = false) : void {
> if (!is_null($columns)) {
$columns = implode(',', $columns);
< set_config('enabledcol', $columns, 'qbank_columnsortorder');
> }
> self::save_preference('enabledcol', $columns, $global);
> }
>
> /**
> * Hidden Columns.
> *
> * @param ?array $columns List of hidden columns. Null value clears the setting.
> * @param bool $global save this as a global default, rather than a user preference?
> */
> public static function set_hidden_columns(?array $columns, bool $global = false) : void {
> if (!is_null($columns)) {
> $columns = implode(',', $columns);
> }
> self::save_preference('hiddencols', $columns, $global);
> }
>
> /**
> * Column size.
> *
> * @param ?string $sizes columns with width. Null value clears the setting.
> * @param bool $global save this as a global default, rather than a user preference?
> */
> public static function set_column_size(?string $sizes, bool $global = false) : void {
> self::save_preference('colsize', $sizes, $global);
> }
>
> /**
> * Save Preferences.
> *
> * @param string $name name of a configuration
> * @param ?string $value value of a configuration. Null value clears the setting.
> * @param bool $global save this as a global default, rather than a user preference?
> */
> private static function save_preference(string $name, ?string $value, bool $global = false): void {
> if ($global) {
> require_capability('moodle/site:config', context_system::instance());
> set_config($name, $value, 'qbank_columnsortorder');
> } else {
> set_user_preference("qbank_columnsortorder_{$name}", $value);
> }
}
/**
* Get qbank.
*
* @return view
*/
< protected function get_questionbank(): view {
> public function get_questionbank(): view {
$course = (object) ['id' => 0];
$context = context_system::instance();
$contexts = new question_edit_contexts($context);
> $category = question_make_default_categories($contexts->all());
// Dummy call to get the objects without error.
> $params = ['cat' => $category->id . ',' . $context->id];
< $questionbank = new view($contexts, new moodle_url('/question/dummyurl.php'), $course, null);
> $questionbank = new preview_view(
> $contexts,
> new moodle_url('/question/bank/columnsortorder/sortcolumns.php'),
> $course,
> null,
> $params
> );
return $questionbank;
}
/**
* Get enabled columns.
*
* @return array
*/
public function get_columns(): array {
$columns = [];
foreach ($this->get_questionbank()->get_visiblecolumns() as $key => $column) {
if ($column->get_name() === 'checkbox') {
continue;
}
< $classelements = explode('\\', $key);
$columns[] = (object) [
'class' => get_class($column),
'name' => $column->get_title(),
< 'colname' => end($classelements),
> 'colname' => $column->get_column_name(),
> 'id' => $column->get_column_id(),
];
}
return $columns;
}
/**
* Get disabled columns.
*
* @return array
*/
public function get_disabled_columns(): array {
$disabled = [];
if ($this->disabledcolumns) {
< foreach ($this->disabledcolumns as $class => $value) {
< if (strpos($class, 'qbank_customfields\custom_field_column') !== false) {
< $class = explode('\\', $class);
< $disabledname = array_pop($class);
< $class = implode('\\', $class);
< $disabled[] = (object) [
< 'disabledname' => $disabledname,
< ];
< } else {
< $columnobject = new $class($this->get_questionbank());
< $disabled[] = (object) [
> foreach (array_keys($this->disabledcolumns) as $column) {
> [$classname, $columnname] = explode(column_base::ID_SEPARATOR, $column, 2);
> $columnobject = $classname::from_column_name($this->get_questionbank(), $columnname);
> $disabled[$column] = (object) [
'disabledname' => $columnobject->get_title(),
];
}
}
< }
return $disabled;
}
/**
* Updates enabled and disabled config for 'qbank_columnsortorder' plugin.
*
* @param array $enabledcolumns Enabled columns to set.
* @param array $disabledcolumns Disabled columns to set.
*/
protected function update_config($enabledcolumns, $disabledcolumns): void {
if (!empty($enabledcolumns)) {
$configenabled = implode(',', array_flip($enabledcolumns));
set_config('enabledcol', $configenabled, 'qbank_columnsortorder');
}
if (!empty($disabledcolumns)) {
$configdisabled = implode(',', array_flip($disabledcolumns));
set_config('disabledcol', $configdisabled, 'qbank_columnsortorder');
} else {
set_config('disabledcol', null, 'qbank_columnsortorder');
}
}
/**
* Enables columns.
*
* @param string $plugin Plugin type and name ie: qbank_viewcreator.
*/
public function enable_columns(string $plugin): void {
$enabledcolumns = [];
$disabledcolumns = [];
if ($this->columnorder) {
$enabledcolumns = $this->columnorder;
}
if ($this->disabledcolumns) {
$disabledcolumns = $this->disabledcolumns;
foreach ($disabledcolumns as $class => $column) {
if (strpos($class, $plugin) !== false) {
$enabledcolumns[$class] = $class;
if (isset($disabledcolumns[$class])) {
unset($disabledcolumns[$class]);
}
}
}
}
$this->update_config($enabledcolumns, $disabledcolumns);
}
/**
* Disables columns.
*
* @param string $plugin Plugin type and name ie: qbank_viewcreator.
*/
public function disable_columns(string $plugin): void {
$disabledcolumns = [];
$enabledcolumns = [];
$allcolumns = $this->get_columns();
if ($this->disabledcolumns) {
$disabledcolumns = $this->disabledcolumns;
}
if ($this->columnorder) {
$enabledcolumns = $this->columnorder;
}
foreach ($allcolumns as $column) {
< if (strpos($column->class, $plugin) !== false) {
< if ($column->class === 'qbank_customfields\custom_field_column') {
< $disabledcolumns[$column->class . '\\' . $column->colname] = $column->class . '\\' . $column->colname;
< if (isset($enabledcolumns[$column->class . '\\' . $column->colname])) {
< unset($enabledcolumns[$column->class. '\\' . $column->colname]);
< }
< } else {
< $disabledcolumns[$column->class] = $column->class;
< if (isset($enabledcolumns[$column->class])) {
< unset($enabledcolumns[$column->class]);
< }
> if (str_contains($column->class, $plugin)) {
> $disabledcolumns[$column->id] = $column->id;
> if (isset($enabledcolumns[$column->id])) {
> unset($enabledcolumns[$column->id]);
}
}
}
$this->update_config($enabledcolumns, $disabledcolumns);
}
/**
* Orders columns in the question bank view according to config_plugins table 'qbank_columnsortorder' config.
*
< * @param array $ordertosort Unordered array of columns
> * @param array $ordertosort Unordered array of columns, [columnname => class]
* @return array $properorder|$ordertosort Returns array ordered if 'qbank_columnsortorder' config exists.
*/
public function get_sorted_columns($ordertosort): array {
// Check if db has order set.
if (!empty($this->columnorder)) {
// Merge new order with old one.
$columnsortorder = $this->columnorder;
asort($columnsortorder);
$columnorder = [];
< foreach ($columnsortorder as $classname => $colposition) {
< $colname = explode('\\', $classname);
< if (strpos($classname, 'qbank_customfields\custom_field_column') !== false) {
< unset($colname[0]);
< $classname = implode('\\', $colname);
< // Checks if custom column still exists.
< if (array_key_exists($classname, $ordertosort)) {
< $columnorder[$classname] = $colposition;
< } else {
< $configtounset = str_replace('\\', '\\\\', $classname);
< // Cleans config db.
< unset_config($configtounset, 'column_sortorder');
< }
< } else {
< $columnorder[end($colname)] = $colposition;
> foreach ($columnsortorder as $columnid => $colposition) {
> if (array_key_exists($columnid, $ordertosort)) {
> $columnorder[$columnid] = $colposition;
}
}
$properorder = array_merge($columnorder, $ordertosort);
// Always have the checkbox at first column position.
< if (isset($properorder['checkbox_column'])) {
< $checkboxfirstelement = $properorder['checkbox_column'];
< unset($properorder['checkbox_column']);
< $properorder = array_merge(['checkbox_column' => $checkboxfirstelement], $properorder);
> $checkboxid = 'core_question\local\bank\checkbox_column' . column_base::ID_SEPARATOR . 'checkbox_column';
> if (isset($properorder[$checkboxid])) {
> $checkboxfirstelement = $properorder[$checkboxid];
> unset($properorder[$checkboxid]);
> $properorder = array_merge([
> $checkboxid => $checkboxfirstelement
> ], $properorder);
}
return $properorder;
}
return $ordertosort;
> }
}
>
}
> /**
> * Given an array of columns, set the isvisible attribute according to $this->hiddencolumns and $this->disabledcolumns.
> *
> * @param column_base[] $columns
> * @return array
> */
> public function set_columns_visibility(array $columns): array {
> foreach ($columns as $column) {
> if (!is_object($column)) {
> continue;
> }
> $columnid = $column->get_column_id();
>
> $column->isvisible = !in_array($columnid, $this->hiddencolumns) && !array_key_exists($columnid, $this->disabledcolumns);
> }
> return $columns;
> }
>
> /**
> * Return $this->colsize mapped as an array of column name => width, excluding empty sizes.
> *
> * @return array
> */
> public function get_colsize_map(): array {
> $sizes = array_reduce($this->colsize, function($result, $colsize) {
> $result[$colsize->column] = $colsize->width;
> return $result;
> }, []);
> return array_filter($sizes);
> }
>
> /**
> * Return an array of hidden columns as an array of class => column name
> *
> * @return array
> */
> public function get_hidden_columns(): array {
> return array_reduce($this->hiddencolumns, function($result, $hiddencolumn) {
> [$columnclass, $columnname] = explode(column_base::ID_SEPARATOR, $hiddencolumn, 2);
> $result[$hiddencolumn] = $columnclass::from_column_name($this->get_questionbank(), $columnname)->get_title();
> return $result;
> }, []);
> }
>
> public function get_column_width(column_base $column): string {
> $colsizemap = $this->get_colsize_map();
> $columnid = $column->get_column_id();
> if (array_key_exists($columnid, $colsizemap)) {
> return $colsizemap[$columnid] . 'px';
> }
> return parent::get_column_width($column);
> }
>
> public function get_column_actions(view $qbank): array {
> return [
> new column_action_move($qbank),
> new column_action_remove($qbank),
> new column_action_resize($qbank),
> ];