MDL-78962 core/loadingicon: remove jQuery requirement in the API
[moodle.git] / rating / classes / privacy / provider.php
blob864ec4f487278ab330940e93cf8e1f9b086f4067
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Privacy Subsystem implementation for core_ratings.
20 * @package core_rating
21 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 namespace core_rating\privacy;
27 use \core_privacy\local\metadata\collection;
28 use \core_privacy\local\request\userlist;
30 defined('MOODLE_INTERNAL') || die();
32 require_once($CFG->dirroot . '/rating/lib.php');
34 /**
35 * Privacy Subsystem implementation for core_ratings.
37 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class provider implements
41 // The ratings subsystem contains data.
42 \core_privacy\local\metadata\provider,
44 // The ratings subsystem is only ever used to store data for other components.
45 // It does not store any data of its own and does not need to implement the \core_privacy\local\request\subsystem\provider
46 // as a result.
48 // The ratings subsystem provides a data service to other components.
49 \core_privacy\local\request\subsystem\plugin_provider,
50 \core_privacy\local\request\shared_userlist_provider
53 /**
54 * Returns metadata about the ratings subsystem.
56 * @param collection $collection The initialised collection to add items to.
57 * @return collection A listing of user data stored through the subsystem.
59 public static function get_metadata(collection $collection) : collection {
60 // The table 'rating' cotains data that a user has entered.
61 // It stores the user-entered rating alongside a mapping to describe what was mapped.
62 $collection->add_database_table('rating', [
63 'rating' => 'privacy:metadata:rating:rating',
64 'userid' => 'privacy:metadata:rating:userid',
65 'timecreated' => 'privacy:metadata:rating:timecreated',
66 'timemodified' => 'privacy:metadata:rating:timemodified',
67 ], 'privacy:metadata:rating');
69 return $collection;
72 /**
73 * Export all ratings which match the specified component, areaid, and itemid.
75 * If requesting ratings for a users own content, and you wish to include all ratings of that content, specify
76 * $onlyuser as false.
78 * When requesting ratings for another users content, you should only export the ratings that the specified user
79 * made themselves.
81 * @param int $userid The user whose information is to be exported
82 * @param \context $context The context being stored.
83 * @param array $subcontext The subcontext within the context to export this information
84 * @param string $component The component to fetch data from
85 * @param string $ratingarea The ratingarea that the data was stored in within the component
86 * @param int $itemid The itemid within that ratingarea
87 * @param bool $onlyuser Whether to only export ratings that the current user has made, or all ratings
89 public static function export_area_ratings(
90 int $userid,
91 \context $context,
92 array $subcontext,
93 string $component,
94 string $ratingarea,
95 int $itemid,
96 bool $onlyuser = true
97 ) {
98 global $DB;
100 $rm = new \rating_manager();
101 $ratings = $rm->get_all_ratings_for_item((object) [
102 'context' => $context,
103 'component' => $component,
104 'ratingarea' => $ratingarea,
105 'itemid' => $itemid,
108 if ($onlyuser) {
109 $ratings = array_filter($ratings, function($rating) use ($userid){
110 return ($rating->userid == $userid);
114 if (empty($ratings)) {
115 return;
118 $toexport = array_map(function($rating) {
119 return (object) [
120 'rating' => $rating->rating,
121 'author' => $rating->userid,
123 }, $ratings);
125 $writer = \core_privacy\local\request\writer::with_context($context)
126 ->export_related_data($subcontext, 'rating', $toexport);
130 * Get the SQL required to find all submission items where this user has had any involvements.
132 * If possible an inner join should be used.
134 * @param string $alias The name of the table alias to use.
135 * @param string $component The na eof the component to fetch ratings for.
136 * @param string $ratingarea The rating area to fetch results for.
137 * @param string $itemidjoin The right-hand-side of the JOIN ON clause.
138 * @param int $userid The ID of the user being stored.
139 * @param bool $innerjoin Whether to use an inner join (preferred)
140 * @return \stdClass
142 public static function get_sql_join($alias, $component, $ratingarea, $itemidjoin, $userid, $innerjoin = false) {
143 static $count = 0;
144 $count++;
146 $userwhere = '';
148 if ($innerjoin) {
149 // Join the rating table with the specified alias and the relevant join params.
150 $join = "JOIN {rating} {$alias} ON ";
151 $join .= "{$alias}.itemid = {$itemidjoin}";
153 $userwhere .= "{$alias}.userid = :ratinguserid{$count} AND ";
154 $userwhere .= "{$alias}.component = :ratingcomponent{$count} AND ";
155 $userwhere .= "{$alias}.ratingarea = :ratingarea{$count}";
156 } else {
157 // Join the rating table with the specified alias and the relevant join params.
158 $join = "LEFT JOIN {rating} {$alias} ON ";
159 $join .= "{$alias}.userid = :ratinguserid{$count} AND ";
160 $join .= "{$alias}.component = :ratingcomponent{$count} AND ";
161 $join .= "{$alias}.ratingarea = :ratingarea{$count} AND ";
162 $join .= "{$alias}.itemid = {$itemidjoin}";
164 // Match against the specified user.
165 $userwhere = "{$alias}.id IS NOT NULL";
168 $params = [
169 'ratingcomponent' . $count => $component,
170 'ratingarea' . $count => $ratingarea,
171 'ratinguserid' . $count => $userid,
174 $return = (object) [
175 'join' => $join,
176 'params' => $params,
177 'userwhere' => $userwhere,
179 return $return;
183 * Deletes all ratings for a specified context, component, ratingarea and itemid.
185 * Only delete ratings when the item itself was deleted.
187 * We never delete ratings for one user but not others - this may affect grades, therefore ratings
188 * made by particular user are not considered personal information.
190 * @param \context $context Details about which context to delete ratings for.
191 * @param string $component Component to delete.
192 * @param string $ratingarea Rating area to delete.
193 * @param int $itemid The item ID for use with deletion.
195 public static function delete_ratings(\context $context, string $component = null,
196 string $ratingarea = null, int $itemid = null) {
197 global $DB;
199 $options = ['contextid' => $context->id];
200 if ($component) {
201 $options['component'] = $component;
203 if ($ratingarea) {
204 $options['ratingarea'] = $ratingarea;
206 if ($itemid) {
207 $options['itemid'] = $itemid;
210 $DB->delete_records('rating', $options);
214 * Deletes all tag instances for given context, component, itemtype using subquery for itemids
216 * In most situations you will want to specify $userid as null. Per-user tag instances
217 * are possible in Tags API, however there are no components or standard plugins that actually use them.
219 * @param \context $context Details about which context to delete ratings for.
220 * @param string $component Component to delete.
221 * @param string $ratingarea Rating area to delete.
222 * @param string $itemidstest an SQL fragment that the itemid must match. Used
223 * in the query like WHERE itemid $itemidstest. Must use named parameters,
224 * and may not use named parameters called contextid, component or ratingarea.
225 * @param array $params any query params used by $itemidstest.
227 public static function delete_ratings_select(\context $context, string $component,
228 string $ratingarea, $itemidstest, $params = []) {
229 global $DB;
230 $params += ['contextid' => $context->id, 'component' => $component, 'ratingarea' => $ratingarea];
231 $DB->delete_records_select('rating',
232 'contextid = :contextid AND component = :component AND ratingarea = :ratingarea AND itemid ' . $itemidstest,
233 $params);
237 * Add the list of users who have rated in the specified constraints.
239 * @param userlist $userlist The userlist to add the users to.
240 * @param string $alias An alias prefix to use for rating selects to avoid interference with your own sql.
241 * @param string $component The component to check.
242 * @param string $area The rating area to check.
243 * @param string $insql The SQL to use in a sub-select for the itemid query.
244 * @param array $params The params required for the insql.
246 public static function get_users_in_context_from_sql(
247 userlist $userlist, string $alias, string $component, string $area, string $insql, $params) {
248 // Discussion authors.
249 $sql = "SELECT {$alias}.userid
250 FROM {rating} {$alias}
251 WHERE {$alias}.component = :{$alias}component
252 AND {$alias}.ratingarea = :{$alias}ratingarea
253 AND {$alias}.itemid IN ({$insql})";
255 $params["{$alias}component"] = $component;
256 $params["{$alias}ratingarea"] = $area;
258 $userlist->add_from_sql('userid', $sql, $params);