MDL-29479 Introducing a new capability moodle/grade:managegradingforms
[moodle.git] / grade / grading / lib.php
CommitLineData
4333580e
DM
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Advanced grading methods support
20 *
21 * @package core
22 * @subpackage grading
23 * @copyright 2011 David Mudrak <david@moodle.com>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29/**
30 * Factory method returning an instance of the grading manager
31 *
32 * @param stdClass $context
33 * @param string $component the frankenstyle name of the component
8a4acb3a 34 * @param string $area the name of the gradable area
4333580e
DM
35 * @return grading_manager
36 */
8a4acb3a 37function get_grading_manager($context = null, $component = null, $area = null) {
4333580e
DM
38
39 $manager = new grading_manager();
40
41 if (!is_null($context)) {
42 $manager->set_context($context);
43 }
44
45 if (!is_null($component)) {
46 $manager->set_component($component);
47 }
48
8a4acb3a
DM
49 if (!is_null($area)) {
50 $manager->set_area($area);
4333580e
DM
51 }
52
53 return $manager;
54}
55
56/**
57 * General class providing access to common grading features
58 *
59 * Fully initialized instance of the grading manager operates over a single
60 * gradable area. It is possible to work with a partially initialized manager
8a4acb3a
DM
61 * that knows just context and component without known area, for example.
62 * It is also possible to change context, component and area of an existing
4333580e
DM
63 * manager. Such pattern is used when copying form definitions, for example.
64 */
65class grading_manager {
66
67 /** @var stdClass the context */
68 protected $context;
69
70 /** @var string the frankenstyle name of the component */
71 protected $component;
72
73 /** @var string the name of the gradable area */
8a4acb3a 74 protected $area;
4333580e
DM
75
76 /**
77 * Sets the context the manager operates on
78 *
79 * @param stdClass $context
80 */
81 public function set_context(stdClass $context) {
82 $this->context = $context;
83 }
84
85 /**
86 * Sets the component the manager operates on
87 *
88 * @param string $component the frankenstyle name of the component
89 */
90 public function set_component($component) {
91 $this->component = $component;
92 }
93
94 /**
8a4acb3a 95 * Sets the area the manager operates on
4333580e 96 *
8a4acb3a 97 * @param string $area the name of the gradable area
4333580e 98 */
8a4acb3a
DM
99 public function set_area($area) {
100 $this->area = $area;
4333580e
DM
101 }
102
103 /**
104 * Returns the list of available grading methods in the given context
105 *
106 * Basically this returns the list of installed grading plugins with an empty value
107 * for simple direct grading. In the future, the list of available methods may be
108 * controlled per-context.
109 *
110 * Requires the context property to be set in advance.
6c9e506c
DM
111 *
112 * @param bool $includenone should the 'Simple direct grading' be included
4333580e
DM
113 * @return array of the (string)name => (string)localized title of the method
114 */
6c9e506c 115 public function get_available_methods($includenone = true) {
4333580e
DM
116
117 $this->ensure_isset(array('context'));
118
6c9e506c
DM
119 if ($includenone) {
120 $list = array('' => get_string('gradingmethodnone', 'core_grading'));
121 } else {
122 $list = array();
123 }
124
125 foreach (get_plugin_list('gradingform') as $name => $location) {
126 $list[$name] = get_string('pluginname', 'gradingform_'.$name);
127 }
128
129 return $list;
4333580e
DM
130 }
131
132 /**
133 * Returns the list of gradable areas in the given context and component
134 *
135 * This performs a callback to the library of the relevant plugin to obtain
136 * the list of supported areas.
137 * @return array of (string)areacode => (string)localized title of the area
138 */
139 public function get_available_areas() {
140 global $CFG;
141
142 $this->ensure_isset(array('context', 'component'));
143
144 // example: if the given context+component lead to mod_assignment, this method
145 // will do something like
146 // require_once($CFG->dirroot.'/mod/assignment/lib.php');
147 // return assignment_gradable_area_list();
148
149 // todo - hardcoded list for now
150 return array('submission' => get_string('assignmentsubmission', 'assignment'));
151 }
152
153 /**
8a4acb3a 154 * Returns the currently active grading method in the gradable area
4333580e 155 *
64402867 156 * @return string|null the name of the grading plugin of null if it has not been set
4333580e 157 */
8a4acb3a 158 public function get_active_method() {
64402867
DM
159 global $DB;
160
161 $this->ensure_isset(array('context', 'component', 'area'));
162
163 // get the current grading area record if it exists
164 $area = $DB->get_record('grading_areas',
165 array('contextid' => $this->context->id, 'component' => $this->component, 'areaname' => $this->area), 'id,activemethod', IGNORE_MISSING);
166
167 if (empty($area)) {
168 // no area record yet
169 return null;
170 }
171
172 return $area->activemethod;
173 }
174
175 /**
176 * Sets the currently active grading method in the gradable area
177 *
178 * @param string $method the method name, eg 'rubric' (must be available)
179 */
180 public function set_active_method($method) {
181 global $DB;
182
8a4acb3a 183 $this->ensure_isset(array('context', 'component', 'area'));
64402867
DM
184
185 // make sure the passed method is a valid plugin name
186 if ('gradingform_'.$method !== clean_param('gradingform_'.$method, PARAM_COMPONENT)) {
187 throw new moodle_exception('invalid_method_name', 'core_grading');
188 }
189 $available = $this->get_available_methods(false);
190 if (!array_key_exists($method, $available)) {
191 throw new moodle_exception('invalid_method_name', 'core_grading');
192 }
193
194 // get the current grading area record if it exists
195 $area = $DB->get_record('grading_areas',
196 array('contextid' => $this->context->id, 'component' => $this->component, 'areaname' => $this->area), 'id,activemethod', IGNORE_MISSING);
197
198 if (empty($area)) {
199 // no area record yet, create one with the active method set
200 $area = array(
201 'contextid' => $this->context->id,
202 'component' => $this->component,
203 'areaname' => $this->area,
204 'activemethod' => $method);
205 $DB->insert_record('grading_areas', $area);
206
207 } else {
208 // update the existing record if needed
209 if ($area->activemethod != $method) {
210 $DB->set_field('grading_areas', 'activemethod', $method, array('id' => $area->id));
211 }
212 }
4333580e
DM
213 }
214
64402867 215
4333580e
DM
216 /**
217 * Make sure that the given properties were set to some not-null value
218 *
219 * @param array $properties the list of properties
220 * @throws coding_exception
221 */
222 private function ensure_isset(array $properties) {
223 foreach ($properties as $property) {
224 if (!isset($this->$property)) {
225 throw new coding_exception('The property '.$property.' is not set.');
226 }
227 }
228 }
229}