Commit 592ec736 authored by Aaron Wells's avatar Aaron Wells
Browse files

Refactoring progress bar to remove serialize() and improve pluggability

Bug 1259538

Change-Id: Ia16408369a06516e4bfebe3c0d92e77c17303678
parent d6754a6c
......@@ -51,8 +51,19 @@ $institutionselector = pieform(array(
// Selected artefacts that count towards completing progress bar
if ($data = get_field('institution_data', 'value', 'institution', $institution, 'type', 'progressbar')) {
$selected = unserialize($data);
$recs = get_records_select_array('institution_config', 'institution=? and field like \'progressbaritem_%\'', array($institution), 'field', 'field, value');
if ($recs) {
$selected = array();
foreach($recs as $rec) {
$obj = new stdClass();
$obj->raw = $rec->field;
$parts = explode('_', $rec->field);
// Check format
if (count($parts) < 3) {
continue;
}
$selected[$rec->field] = $rec->value;
}
}
else {
$selected = array();
......@@ -63,149 +74,144 @@ $sitelocked = (array) get_column('institution_locked_profile_field', 'profilefie
$instlocked = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', $institution);
$locked = array_merge($sitelocked, $instlocked);
// Figure out the form elements in the configuration form
$elements = array();
$possibleitems = artefact_get_progressbar_items();
foreach($possibleitems as $plugin => $itemlist) {
$subelements = array();
$fscollapsed = true;
foreach($itemlist as $artefact) {
$pbname = "progressbaritem_{$artefact->plugin}_{$artefact->name}";
// Check if this one is a locked profile field.
if ($plugin == 'internal' && in_array($artefact->name, $locked)) {
$islocked = true;
}
else {
$islocked = false;
}
function build_artefact_options($name, $values) {
global $locked;
if (is_null($name)) {
throw new InvalidArgumentException("Artefact category is expected, but not defined.");
}
else {
// Select all possible artefacts for progressbar except for those artefactst
// that wish to opt out. Also include special case options.
$records = PluginArtefact::get_progressbar_options($name);
$elements = array();
foreach ($records as $artefact) {
if ($artefact->iscountable) {
$options = array(
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
10 => '10',
15 => '15',
20 => '20',
25 => '25',
50 => '50',
100 => '100',
);
$elements[$artefact->name] = array(
'type' => 'select',
'title' => $artefact->title,
'disabled' => ($artefact->active && !in_array($artefact->name, $locked) ? false : true),
'defaultvalue' => (array_key_exists($artefact->name, $values) && isset($values[$artefact->name])
&& !in_array($artefact->name, $locked) ? $values[$artefact->name] : null),
'options' => $options
);
}
else {
$elements[$artefact->name] = array(
'type' => 'checkbox',
'title' => $artefact->title,
'disabled' => ($artefact->active && !in_array($artefact->name, $locked) ? false : true),
'defaultvalue' => (array_key_exists($artefact->name, $values) && isset($values[$artefact->name])
&& !in_array($artefact->name, $locked) ? $values[$artefact->name] : null),
);
if (in_array($artefact->name, array('email'))) {
$elements[$artefact->name]['defaultvalue'] = 1;
$elements[$artefact->name]['readonly'] = 1;
}
}
// Check if this one has a default value (i.e. a value stored in the DB)
if (!$islocked && array_key_exists($pbname, $selected)) {
$defaultvalue = $selected[$pbname];
}
else {
$defaultvalue = null;
}
return $elements;
// If there are any selected elements in this fieldset, don't pre-collapse it.
$fscollapsed = $fscollapsed && !$defaultvalue;
if ($artefact->iscountable) {
$options = array(
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
10 => '10',
15 => '15',
20 => '20',
25 => '25',
50 => '50',
100 => '100',
);
$subelements[$pbname] = array(
'type' => 'select',
'title' => $artefact->title,
'disabled' => ($artefact->active && !$islocked ? false : true),
'defaultvalue' => $defaultvalue,
'options' => $options
);
}
else {
$subelements[$pbname] = array(
'type' => 'checkbox',
'title' => $artefact->title,
'disabled' => ($artefact->active && !$islocked ? false : true),
'defaultvalue' => $defaultvalue,
);
}
}
$elements["fs{$plugin}"] = array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => $fscollapsed,
'legend' => get_string('pluginname', "artefact.{$plugin}"),
'elements' => $subelements,
);
}
$elements['institution'] = array(
'type' => 'hidden',
'value' => $institution,
);
$elements['submit'] = array(
'type' => 'submit',
'value' => get_string('submit')
);
$form = pieform(array(
'name' => 'progressbarform',
'renderer' => 'table',
'plugintype' => 'core',
'pluginname' => 'admin',
'elements' => array(
'fsinternal' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('profile', 'artefact.internal'),
'elements' => build_artefact_options('internal', $selected)
),
'fsresume' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('resume', 'artefact.resume'),
'elements' => build_artefact_options('resume', $selected)
),
'fsplans' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('plan', 'artefact.plans'),
'elements' => build_artefact_options('plans', $selected)
),
'fsblog' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('blog', 'artefact.blog'),
'elements' => build_artefact_options('blog', $selected)
),
'fsfile' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('file', 'artefact.file'),
'elements' => build_artefact_options('file', $selected)
),
'fssocial' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('Social', 'artefact.social'),
'elements' => build_artefact_options('social', $selected)
),
'institution' => array(
'type' => 'hidden',
'value' => $institution,
),
'submit' => array(
'type' => 'submit',
'value' => get_string('submit')
),
)
'elements' => $elements,
));
function progressbarform_submit(Pieform $form, $values) {
global $SESSION, $USER;
function progressbarform_validate(Pieform $form, $values) {
global $USER;
$inst = $values['institution'];
if (empty($inst) || !$USER->can_edit_institution($inst)) {
$SESSION->add_error_msg(get_string('notadminforinstitution', 'admin'));
redirect('/admin/users/progressbar.php');
}
}
unset($values['submit']);
unset($values['sesskey']);
unset($values['institution']);
$where = (object) array(
'institution' => $inst,
'type' => 'progressbar',
);
$data = (object) array(
'ctime' => db_format_timestamp(time()),
'institution' => $inst,
'type' => 'progressbar',
'value' => serialize($values)
);
function progressbarform_submit(Pieform $form, $values) {
global $SESSION, $USER, $possibleitems;
$institution = $values['institution'];
// Pre-fetching the current settings to reduce SELECT queries
$currentsettings = get_records_select_assoc('institution_config', 'institution=? and field like \'progressbaritem_%\'', array($institution), 'field', 'field, value');
if (!$currentsettings) {
$currentsettings = array();
}
foreach ($possibleitems as $plugin => $pluginitems) {
foreach ($pluginitems as $artefact) {
$itemname = "progressbaritem_{$plugin}_{$artefact->name}";
// Format the value into an integer or 0/1
$val = $values[$itemname];
if ($artefact->iscountable) {
$val = (int) $val;
}
else {
$val = (int)((bool) $val);
}
// Update the record if it already exists, or create the record if it doesn't
if (array_key_exists($itemname, $currentsettings)) {
if ($val) {
set_field('institution_config', 'value', $val, 'institution', $institution, 'field', $itemname);
}
else {
delete_records('institution_config', 'institution', $institution, 'field', $itemname);
}
}
else {
if ($val) {
insert_record('institution_config', (object) array('institution'=>$institution, 'field'=>$itemname, 'value'=>$val));
}
}
}
}
ensure_record_exists('institution_data', $where, $data);
$SESSION->add_ok_msg(get_string('progressbarsaved', 'admin'));
redirect('/admin/users/progressbar.php?institution=' . $inst);
redirect('/admin/users/progressbar.php?institution=' . $institution);
}
......
......@@ -124,6 +124,10 @@ class PluginArtefactComment extends PluginArtefact {
safe_require('notification', 'internal');
PluginNotificationInternal::clean_notifications(array('feedback'));
}
public static function has_progressbar_options() {
return false;
}
}
class ArtefactTypeComment extends ArtefactType {
......
......@@ -708,6 +708,10 @@ class ArtefactTypeEmail extends ArtefactTypeProfileField {
}
return array('html' => $html, 'javascript' => null);
}
static public function is_allowed_in_progressbar() {
return false;
}
}
class ArtefactTypeStudentid extends ArtefactTypeCachedProfileField {}
......
......@@ -102,94 +102,15 @@ abstract class PluginArtefact extends Plugin {
return array();
}
/**
* Returns any artefact options allowed to be included in the progress_bar
* @param string $plugin The plugin artefact type
* @return array of objects each containing name, title, plugin, active, iscountable
*/
public static function get_progressbar_options($plugin) {
if (file_exists(get_config('docroot') . 'artefact/' . $plugin . '/lib.php')) {
require_once(get_config('docroot') . 'artefact/' . $plugin . '/lib.php');
}
else {
return array();
}
$records = array();
$classname = generate_class_name('artefact', $plugin);
$names = call_static_method($classname, 'get_artefact_types');
foreach ($names as $name) {
// check if any of the artefact types want to opt out
if (call_static_method('ArtefactType' . ucfirst($name), 'is_allowed_in_progressbar') == false) {
continue;
}
$record = new stdClass();
$record->name = $name;
$record->title = (method_exists('ArtefactType' . ucfirst($name), 'get_title_progressbar')) ? call_static_method('ArtefactType' . ucfirst($name), 'get_title_progressbar') : ucfirst(get_string($name, 'artefact.' . $plugin));
$record->plugin = call_static_method($classname, 'get_plugin_name');
$record->active = (method_exists($classname, 'is_active')) ? call_static_method($classname, 'is_active') : true;
$record->iscountable = call_static_method('ArtefactType' . ucfirst($name), 'is_countable_progressbar');
$records[] = $record;
}
// add any special cases
if (is_array($specials = call_static_method($classname, 'progressbar_additional_items'))) {
foreach ($specials as $special) {
array_push($records, $special);
}
}
return $records;
}
/**
* Dealing with things to count in progressbar that are not true artefacts
* and therefore are not countable by adding up how many instances exist in
* the artefact table. Or if you want to count an artefact differently.
* For example: Social -> Make a friend
* @param string name of artefact plugin
* @return array of objects each containing artefacttype, completed
* (where completed represents the number completed)
* Indicates whether this particular plugin has any progress bar options. By default, any new plugin
* will have progress bar options, for creating at least one of the artefact.
*
* @return boolean
*/
public static function get_progressbar_metaartefact($plugin) {
if (file_exists(get_config('docroot') . 'artefact/' . $plugin . '/lib.php')) {
require_once(get_config('docroot') . 'artefact/' . $plugin . '/lib.php');
}
else {
return array();
}
$results = array();
$classname = generate_class_name('artefact', $plugin);
// Check the artefacttypes to see if they have a special metaartefact count
$names = call_static_method($classname, 'get_artefact_types');
foreach ($names as $name) {
$is_metaartefact = call_static_method('ArtefactType' . ucfirst($name), 'is_metaartefact');
if ($is_metaartefact) {
$meta = call_user_func($classname . '::progressbar_metaartefact_count', $name);
if (is_object($meta)) {
array_push($results, $meta);
}
}
}
// Also check the special artefacts
if (is_array($specials = call_static_method($classname, 'progressbar_additional_items'))) {
foreach ($specials as $special) {
if (empty($special->is_metaartefact)) {
// check to see if it can have mataartefact count
$special->is_metaartefact = call_static_method('ArtefactType' . ucfirst($special->name), 'is_metaartefact');
}
if (!empty($special->is_metaartefact)) {
// Now check if they have a special metaartefact count
$meta = call_user_func($classname . '::progressbar_metaartefact_count', $special->name);
if (is_object($meta)) {
array_push($results, $meta);
}
}
}
}
return $results;
public static function has_progressbar_options() {
return true;
}
/**
......@@ -1385,6 +1306,14 @@ abstract class ArtefactType {
public static function is_metaartefact() {
return false;
}
/**
* The (optional) custom title of this artefact on the profile completion progress bar config page
* @return mixed FALSE if it should just use the artefact type, a string otherwise
*/
public static function get_title_progressbar() {
return false;
}
}
/**
......@@ -1908,3 +1837,121 @@ function artefact_get_owner_info($ids) {
}
return $data;
}
/**
* Returns any artefact options allowed to be included in the progress_bar
* @param array $onlythese (optional) An array of institution_config options indicating which items to include
* @return array of objects each containing name, title, plugin, active, iscountable
*/
function artefact_get_progressbar_items($onlythese = false) {
if ($onlythese === false) {
$onlytheseplugins = array();
}
else {
$onlytheseplugins = $onlythese;
}
$options = array();
foreach(plugins_installed('artefact') as $plugin) {
if ($onlythese !== false && empty($onlytheseplugins[$plugin->name])) {
continue;
}
safe_require('artefact', $plugin->name);
$pluginclassname = generate_class_name('artefact', $plugin->name);
if (!call_static_method($pluginclassname, 'has_progressbar_options')) {
continue;
}
$artefactoptions = array();
$names = call_static_method($pluginclassname, 'get_artefact_types');
foreach ($names as $name) {
if ($onlythese !== false && empty($onlytheseplugins[$plugin->name][$name])) {
continue;
}
// check if any of the artefact types want to opt out
if (call_static_method('ArtefactType' . ucfirst($name), 'is_allowed_in_progressbar') == false) {
continue;
}
$record = new stdClass();
$record->name = $name;
$record->title = call_static_method('ArtefactType' . ucfirst($name), 'get_title_progressbar');
if (!$record->title) {
$record->title = ucfirst(get_string($name, 'artefact.' . $plugin->name));
}
$record->plugin = call_static_method($pluginclassname, 'get_plugin_name');
$record->active = (method_exists($pluginclassname, 'is_active')) ? call_static_method($pluginclassname, 'is_active') : true;
$record->iscountable = call_static_method('ArtefactType' . ucfirst($name), 'is_countable_progressbar');
$record->ismeta = call_static_method('ArtefactType' . ucfirst($name), 'is_metaartefact');
$artefactoptions[$name] = $record;
}
// add any special cases
if (is_array($specials = call_static_method($pluginclassname, 'progressbar_additional_items'))) {
foreach ($specials as $special) {
if ($onlythese !== false && empty($onlytheseplugins[$plugin->name][$special->name])) {
continue;
}
$special->ismeta = true;
$artefactoptions[$special->name] = $special;
}
}
if ($artefactoptions) {
$options[$plugin->name] = $artefactoptions;
}
}
return $options;
}
/**
* Dealing with things to count in progressbar that are not true artefacts
* and therefore are not countable by adding up how many instances exist in
* the artefact table. Or if you want to count an artefact differently.
* For example: Social -> Make a friend
*
* @param string $plugin name of artefact plugin
* @param array $onlythese (optional) An array of items from artefact_get_progressbar_items, indicating which to include
* @return array of objects each containing artefacttype, completed
* (where completed represents the number completed)
*/
function artefact_get_progressbar_metaartefacts($plugin, $onlythese = false) {
$results = array();
$classname = generate_class_name('artefact', $plugin);
// Check the artefacttypes to see if they have a special metaartefact count
$names = call_static_method($classname, 'get_artefact_types');
foreach ($names as $name) {
if (!array_key_exists($name, $onlythese)) {
continue;
}
$is_metaartefact = call_static_method('ArtefactType' . ucfirst($name), 'is_metaartefact');
if ($is_metaartefact) {
$meta = call_user_func($classname . '::progressbar_metaartefact_count', $name);
if (is_object($meta)) {
array_push($results, $meta);
}
}
}
// Also check the special artefacts
if (is_array($specials = call_static_method($classname, 'progressbar_additional_items'))) {
foreach ($specials as $special) {
if (!array_key_exists($special->name, $onlythese)) {
continue;
}
if (empty($special->is_metaartefact)) {
// check to see if it can have mataartefact count
$special->is_metaartefact = call_static_method('ArtefactType' . ucfirst($special->name), 'is_metaartefact');
}
if (!empty($special->is_metaartefact)) {
// Now check if they have a special metaartefact count
$meta = call_user_func($classname . '::progressbar_metaartefact_count', $special->name);
if (is_object($meta)) {
array_push($results, $meta);
}
}
}
}
return $results;
}
......@@ -12,6 +12,8 @@
defined('INTERNAL') || die();
/* Plans */
$string['pluginname'] = 'Plans';
$string['canteditdontownplan'] = 'You cannot edit this plan because you do not own it.';
$string['description'] = 'Description';
$string['deleteplanconfirm'] = 'Are you sure you wish to delete this plan? Deleting this plan will also remove any tasks it contains.';
......
......@@ -2876,13 +2876,15 @@ function tags_sideblock() {
}
function progressbar_artefact_link($artefacttype, $pluginname) {
function progressbar_artefact_link($pluginname, $artefacttype) {
return call_user_func(generate_class_name('artefact', $pluginname) . '::progressbar_link', $artefacttype);
}
function progressbar_sideblock($preview=false) {
global $USER;
// TODO: Remove this URL param from here, and when previewing pass institution
// by function param instead
$institution = param_alphanum('i', null);
if (is_array($USER->institutions) && count($USER->institutions) > 0) {
// Get all institutions where user is member
......@@ -2906,116 +2908,128 @@ function progressbar_sideblock($preview=false) {
// is also selected as a default value in institution selection box
if ($preview) {
$default = get_column('institution', 'name');
// TODO: Remove this URL param from here, and when previewing pass institution
// by function param instead
$institution = param_alphanum('institution', $default[0]);
}
// Get artefacts that count towards profile completeness
if ($field = get_field('institution_data', 'value', 'institution', $institution, 'type', 'progressbar')) {
$counting = unserialize($field);
if ($counting = get_records_select_assoc('institution_config', 'institution=? and field like \'progressbaritem_%\'', array($institution), 'field', 'field, value')) {
// Without locked ones (site locked and institution locked)
$sitelocked = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', 'mahara');
$instlocked = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', $institution);
$locked = array_merge($sitelocked, $instlocked);
foreach ($counting as $key => $value) {
if (in_array($key, $locked)) {
unset($counting[$key]);
}
foreach ($locked as $l) {
unset($counting["progressbaritem_internal_{$l}"]);
}
foreach ($counting as $key => $value) {
// Set non-selected checkboxes to 0