AutorÃa | Ultima modificación | Ver Log |
<?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/>.
/**
* Provides {@link tool_policy\output\acceptances_filter} class.
*
* @package tool_policy
* @category output
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_policy\output;
use tool_policy\api;
use tool_policy\policy_version;
defined('MOODLE_INTERNAL') || die();
/**
* Implements the widget allowing to filter the acceptance records.
*
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class acceptances_filter implements \templatable, \renderable {
/** @var array $filtersapplied The list of selected filter options. */
protected $filtersapplied;
/** @var string $searchstring */
protected $searchstrings;
/** @var array list of available versions */
protected $versions = null;
/** @var array list of available roles for the filter */
protected $roles;
/** @var array cached list of all available policies, to retrieve use {@link self::get_avaliable_policies()} */
protected $policies;
/** @var int */
const FILTER_SEARCH_STRING = 0;
/** @var int */
const FILTER_POLICYID = 1;
/** @var int */
const FILTER_VERSIONID = 2;
/** @var int */
const FILTER_CAPABILITY_ACCEPT = 3;
/** @var int */
const FILTER_STATUS = 4;
/** @var int */
const FILTER_ROLE = 5;
/**
* Constructor.
*
* @param array $policyid Specified policy id
* @param array $versionid Specified version id
* @param array $filtersapplied The list of selected filter option values.
*/
public function __construct($policyid, $versionid, $filtersapplied) {
$this->filtersapplied = [];
$this->roles = get_assignable_roles(\context_system::instance());
if ($policyid) {
$this->add_filter(self::FILTER_POLICYID, $policyid);
}
if ($versionid) {
$this->add_filter(self::FILTER_VERSIONID, $versionid);
}
foreach ($filtersapplied as $filter) {
if (preg_match('/^([1-9]\d*):(\d+)$/', $filter, $parts)) {
// This is a pre-set filter (policy, version, status, etc.).
$allowmultiple = false;
switch ((int)$parts[1]) {
case self::FILTER_POLICYID:
case self::FILTER_VERSIONID:
case self::FILTER_CAPABILITY_ACCEPT:
case self::FILTER_STATUS:
$value = (int)$parts[2];
break;
case self::FILTER_ROLE:
$value = (int)$parts[2];
if (!array_key_exists($value, $this->roles)) {
continue 2;
}
$allowmultiple = true;
break;
default:
// Unrecognised filter.
continue 2;
}
$this->add_filter((int)$parts[1], $value, $allowmultiple);
} else if (trim($filter) !== '') {
// This is a search string.
$this->add_filter(self::FILTER_SEARCH_STRING, trim($filter), true);
}
}
}
/**
* Adds an applied filter
*
* @param mixed $key
* @param mixed $value
* @param bool $allowmultiple
*/
protected function add_filter($key, $value, $allowmultiple = false) {
if ($allowmultiple || empty($this->get_filter_values($key))) {
$this->filtersapplied[] = [$key, $value];
}
}
/**
* Is there a filter by policy
*
* @return null|int null if there is no filter, otherwise the policy id
*/
public function get_policy_id_filter() {
return $this->get_filter_value(self::FILTER_POLICYID);
}
/**
* Is there a filter by version
*
* @return null|int null if there is no filter, otherwise the version id
*/
public function get_version_id_filter() {
return $this->get_filter_value(self::FILTER_VERSIONID);
}
/**
* Are there filters by search strings
*
* @return string[] array of string filters
*/
public function get_search_strings() {
return $this->get_filter_values(self::FILTER_SEARCH_STRING);
}
/**
* Is there a filter by status (agreed/not agreed).
*
* @return null|0|1 null if there is no filter, 0/1 if there is a filter by status
*/
public function get_status_filter() {
return $this->get_filter_value(self::FILTER_STATUS);
}
/**
* Are there filters by role
*
* @return array list of role ids
*/
public function get_role_filters() {
return $this->get_filter_values(self::FILTER_ROLE);
}
/**
* Is there a filter by capability (can accept/cannot accept).
*
* @return null|0|1 null if there is no filter, 0/1 if there is a filter by capability
*/
public function get_capability_accept_filter() {
return $this->get_filter_value(self::FILTER_CAPABILITY_ACCEPT);
}
/**
* Get all values of the applied filter
*
* @param string $filtername
* @return array
*/
protected function get_filter_values($filtername) {
$values = [];
foreach ($this->filtersapplied as $filter) {
if ($filter[0] == $filtername) {
$values[] = $filter[1];
}
}
return $values;
}
/**
* Get one value of the applied filter
*
* @param string $filtername
* @param string $default
* @return mixed
*/
protected function get_filter_value($filtername, $default = null) {
if ($values = $this->get_filter_values($filtername)) {
$value = reset($values);
return $value;
}
return $default;
}
/**
* Returns all policies that have versions with possible acceptances (excl. drafts and guest-only versions)
*
* @return array|null
*/
public function get_avaliable_policies() {
if ($this->policies === null) {
$this->policies = [];
foreach (\tool_policy\api::list_policies() as $policy) {
// Make a list of all versions that are not draft and are not guest-only.
$policy->versions = [];
if ($policy->currentversion && $policy->currentversion->audience != policy_version::AUDIENCE_GUESTS) {
$policy->versions[$policy->currentversion->id] = $policy->currentversion;
} else {
$policy->currentversion = null;
}
foreach ($policy->archivedversions as $version) {
if ($version->audience != policy_version::AUDIENCE_GUESTS) {
$policy->versions[$version->id] = $version;
}
}
if ($policy->versions) {
$this->policies[$policy->id] = $policy;
}
}
}
return $this->policies;
}
/**
* List of policies that match current filters
*
* @return array of versions to display indexed by versionid
*/
public function get_versions() {
if ($this->versions === null) {
$policyid = $this->get_policy_id_filter();
$versionid = $this->get_version_id_filter();
$this->versions = [];
foreach ($this->get_avaliable_policies() as $policy) {
if ($policyid && $policy->id != $policyid) {
continue;
}
if ($versionid) {
if (array_key_exists($versionid, $policy->versions)) {
$this->versions[$versionid] = $policy->versions[$versionid];
break; // No need to keep searching.
}
} else if ($policy->currentversion) {
$this->versions[$policy->currentversion->id] = $policy->currentversion;
}
}
}
return $this->versions;
}
/**
* Validates if policyid and versionid are valid (if specified)
*/
public function validate_ids() {
$policyid = $this->get_policy_id_filter();
$versionid = $this->get_version_id_filter();
if ($policyid || $versionid) {
$found = array_filter($this->get_avaliable_policies(), function($policy) use ($policyid, $versionid) {
return (!$policyid || $policy->id == $policyid) &&
(!$versionid || array_key_exists($versionid, $policy->versions));
});
if (!$found) {
// Throw exception that policy/version is not found.
throw new \moodle_exception('errorpolicyversionnotfound', 'tool_policy');
}
}
}
/**
* If policyid or versionid is specified return one single policy that needs to be shown
*
* If neither policyid nor versionid is specified this method returns null.
*
* When versionid is specified this method will always return an object (this is validated in {@link self::validate_ids()}
* When only policyid is specified this method either returns the current version of the policy or null if there is
* no current version (for example, it is an old policy).
*
* @return mixed|null
*/
public function get_single_version() {
if ($this->get_version_id_filter() || $this->get_policy_id_filter()) {
$versions = $this->get_versions();
return reset($versions);
}
return null;
}
/**
* Returns URL of the acceptances page with all current filters applied
*
* @return \moodle_url
*/
public function get_url() {
$urlparams = [];
if ($policyid = $this->get_policy_id_filter()) {
$urlparams['policyid'] = $policyid;
}
if ($versionid = $this->get_version_id_filter()) {
$urlparams['versionid'] = $versionid;
}
$i = 0;
foreach ($this->filtersapplied as $filter) {
if ($filter[0] != self::FILTER_POLICYID && $filter[0] != self::FILTER_VERSIONID) {
if ($filter[0] == self::FILTER_SEARCH_STRING) {
$urlparams['unified-filters['.($i++).']'] = $filter[1];
} else {
$urlparams['unified-filters['.($i++).']'] = join(':', $filter);
}
}
}
return new \moodle_url('/admin/tool/policy/acceptances.php', $urlparams);
}
/**
* Creates an option name for the smart select for the version
*
* @param \stdClass $version
* @return string
*/
protected function get_version_option_for_filter($version) {
if ($version->status == policy_version::STATUS_ACTIVE) {
$a = (object)[
'name' => format_string($version->revision),
'status' => get_string('status'.policy_version::STATUS_ACTIVE, 'tool_policy'),
];
return get_string('filterrevisionstatus', 'tool_policy', $a);
} else {
return get_string('filterrevision', 'tool_policy', $version->revision);
}
}
/**
* Build list of filters available for this page
*
* @return array [$availablefilters, $selectedoptions]
*/
protected function build_available_filters() {
$selectedoptions = [];
$availablefilters = [];
$versionid = $this->get_version_id_filter();
$policyid = $versionid ? $this->get_single_version()->policyid : $this->get_policy_id_filter();
// Policies.
$policies = $this->get_avaliable_policies();
if ($policyid) {
// If policy is selected, display only the current policy in the selector.
$selectedoptions[] = $key = self::FILTER_POLICYID . ':' . $policyid;
$version = $versionid ? $policies[$policyid]->versions[$versionid] : reset($policies[$policyid]->versions);
$availablefilters[$key] = get_string('filterpolicy', 'tool_policy', $version->name);
} else {
// If no policy/version is selected display the list of all policies.
foreach ($policies as $policy) {
$firstversion = reset($policy->versions);
$key = self::FILTER_POLICYID . ':' . $policy->id;
$availablefilters[$key] = get_string('filterpolicy', 'tool_policy', $firstversion->name);
}
}
// Versions.
if ($versionid) {
$singleversion = $this->get_single_version();
$selectedoptions[] = $key = self::FILTER_VERSIONID . ':' . $singleversion->id;
$availablefilters[$key] = $this->get_version_option_for_filter($singleversion);
} else if ($policyid) {
foreach ($policies[$policyid]->versions as $version) {
$key = self::FILTER_VERSIONID . ':' . $version->id;
$availablefilters[$key] = $this->get_version_option_for_filter($version);
}
}
// Permissions.
$permissions = [
self::FILTER_CAPABILITY_ACCEPT . ':1' => get_string('filtercapabilityyes', 'tool_policy'),
self::FILTER_CAPABILITY_ACCEPT . ':0' => get_string('filtercapabilityno', 'tool_policy'),
];
if (($currentpermission = $this->get_capability_accept_filter()) !== null) {
$selectedoptions[] = $key = self::FILTER_CAPABILITY_ACCEPT . ':' . $currentpermission;
$permissions = array_intersect_key($permissions, [$key => true]);
}
$availablefilters += $permissions;
// Status.
$statuses = [
self::FILTER_STATUS.':2' => get_string('filterstatusdeclined', 'tool_policy'),
self::FILTER_STATUS.':1' => get_string('filterstatusyes', 'tool_policy'),
self::FILTER_STATUS.':0' => get_string('filterstatuspending', 'tool_policy'),
];
if (($currentstatus = $this->get_status_filter()) !== null) {
$selectedoptions[] = $key = self::FILTER_STATUS . ':' . $currentstatus;
$statuses = array_intersect_key($statuses, [$key => true]);
}
$availablefilters += $statuses;
// Roles.
$currentroles = $this->get_role_filters();
foreach ($this->roles as $roleid => $rolename) {
$key = self::FILTER_ROLE . ':' . $roleid;
$availablefilters[$key] = get_string('filterrole', 'tool_policy', $rolename);
if (in_array($roleid, $currentroles)) {
$selectedoptions[] = $key;
}
}
// Search string.
foreach ($this->get_search_strings() as $str) {
$selectedoptions[] = $str;
$availablefilters[$str] = $str;
}
return [$availablefilters, $selectedoptions];
}
/**
* Function to export the renderer data in a format that is suitable for a mustache template.
*
* @param renderer_base $output Used to do a final render of any components that need to be rendered for export.
* @return \stdClass|array
*/
public function export_for_template(\renderer_base $output) {
$data = new \stdClass();
$data->action = (new \moodle_url('/admin/tool/policy/acceptances.php'))->out(false);
$data->filteroptions = [];
$originalfilteroptions = [];
list($avilablefilters, $selectedoptions) = $this->build_available_filters();
foreach ($avilablefilters as $value => $label) {
$selected = in_array($value, $selectedoptions);
$filteroption = (object)[
'value' => $value,
'label' => $label
];
$originalfilteroptions[] = $filteroption;
$filteroption->selected = $selected;
$data->filteroptions[] = $filteroption;
}
$data->originaloptionsjson = json_encode($originalfilteroptions);
return $data;
}
}