MDL-54205 tool_recyclebin: Adding missing destroy() calls.
[moodle.git] / admin / tool / recyclebin / classes / course_bin.php
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.
13 //
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  * The main interface for recycle bin methods.
19  *
20  * @package    tool_recyclebin
21  * @copyright  2015 University of Kent
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace tool_recyclebin;
27 defined('MOODLE_INTERNAL') || die();
29 define('TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA', 'recyclebin_course');
31 /**
32  * Represents a course's recyclebin.
33  *
34  * @package    tool_recyclebin
35  * @copyright  2015 University of Kent
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class course_bin extends base_bin {
40     /**
41      * @var int The course id.
42      */
43     protected $_courseid;
45     /**
46      * Constructor.
47      *
48      * @param int $courseid Course ID.
49      */
50     public function __construct($courseid) {
51         $this->_courseid = $courseid;
52     }
54     /**
55      * Is this recyclebin enabled?
56      *
57      * @return bool true if enabled, false if not.
58      */
59     public static function is_enabled() {
60         return get_config('tool_recyclebin', 'coursebinenable');
61     }
63     /**
64      * Returns an item from the recycle bin.
65      *
66      * @param int $itemid Item ID to retrieve.
67      * @return \stdClass the item.
68      */
69     public function get_item($itemid) {
70         global $DB;
72         return $DB->get_record('tool_recyclebin_course', array(
73             'id' => $itemid
74         ), '*', MUST_EXIST);
75     }
77     /**
78      * Returns a list of items in the recycle bin for this course.
79      *
80      * @return array the list of items.
81      */
82     public function get_items() {
83         global $DB;
85         return $DB->get_records('tool_recyclebin_course', array(
86             'courseid' => $this->_courseid
87         ));
88     }
90     /**
91      * Store a course module in the recycle bin.
92      *
93      * @param \stdClass $cm Course module
94      * @throws \moodle_exception
95      */
96     public function store_item($cm) {
97         global $CFG, $DB;
99         require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
101         // Get more information.
102         $modinfo = get_fast_modinfo($cm->course);
104         if (!isset($modinfo->cms[$cm->id])) {
105             return; // Can't continue without the module information.
106         }
108         $cminfo = $modinfo->cms[$cm->id];
110         // Check backup/restore support.
111         if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) {
112             return;
113         }
115         // Backup the activity.
116         $user = get_admin();
117         $controller = new \backup_controller(
118             \backup::TYPE_1ACTIVITY,
119             $cm->id,
120             \backup::FORMAT_MOODLE,
121             \backup::INTERACTIVE_NO,
122             \backup::MODE_GENERAL,
123             $user->id
124         );
125         $controller->execute_plan();
127         // Grab the result.
128         $result = $controller->get_results();
129         if (!isset($result['backup_destination'])) {
130             throw new \moodle_exception('Failed to backup activity prior to deletion.');
131         }
133         // Have finished with the controller, let's destroy it, freeing mem and resources.
134         $controller->destroy();
136         // Grab the filename.
137         $file = $result['backup_destination'];
138         if (!$file->get_contenthash()) {
139             throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).');
140         }
142         // Record the activity, get an ID.
143         $activity = new \stdClass();
144         $activity->courseid = $cm->course;
145         $activity->section = $cm->section;
146         $activity->module = $cm->module;
147         $activity->name = $cminfo->name;
148         $activity->timecreated = time();
149         $binid = $DB->insert_record('tool_recyclebin_course', $activity);
151         // Create the location we want to copy this file to.
152         $filerecord = array(
153             'contextid' => \context_course::instance($this->_courseid)->id,
154             'component' => 'tool_recyclebin',
155             'filearea' => TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA,
156             'itemid' => $binid,
157             'timemodified' => time()
158         );
160         // Move the file to our own special little place.
161         $fs = get_file_storage();
162         if (!$fs->create_file_from_storedfile($filerecord, $file)) {
163             // Failed, cleanup first.
164             $DB->delete_records('tool_recyclebin_course', array(
165                 'id' => $binid
166             ));
168             throw new \moodle_exception("Failed to copy backup file to recyclebin.");
169         }
171         // Delete the old file.
172         $file->delete();
174         // Fire event.
175         $event = \tool_recyclebin\event\course_bin_item_created::create(array(
176             'objectid' => $binid,
177             'context' => \context_course::instance($cm->course)
178         ));
179         $event->trigger();
180     }
182     /**
183      * Restore an item from the recycle bin.
184      *
185      * @param \stdClass $item The item database record
186      * @throws \moodle_exception
187      */
188     public function restore_item($item) {
189         global $CFG, $OUTPUT, $PAGE;
191         require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
193         $user = get_admin();
195         // Grab the course context.
196         $context = \context_course::instance($this->_courseid);
198         // Get the files..
199         $fs = get_file_storage();
200         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id,
201             'itemid, filepath, filename', false);
203         if (empty($files)) {
204             throw new \moodle_exception('Invalid recycle bin item!');
205         }
207         if (count($files) > 1) {
208             throw new \moodle_exception('Too many files found!');
209         }
211         // Get the backup file.
212         $file = reset($files);
214         // Get a temp directory name and create it.
215         $tempdir = \restore_controller::get_tempdir_name($context->id, $user->id);
216         $fulltempdir = make_temp_directory('/backup/' . $tempdir);
218         // Extract the backup to tempdir.
219         $fb = get_file_packer('application/vnd.moodle.backup');
220         $fb->extract_to_pathname($file, $fulltempdir);
222         // Define the import.
223         $controller = new \restore_controller(
224             $tempdir,
225             $this->_courseid,
226             \backup::INTERACTIVE_NO,
227             \backup::MODE_GENERAL,
228             $user->id,
229             \backup::TARGET_EXISTING_ADDING
230         );
232         // Prechecks.
233         if (!$controller->execute_precheck()) {
234             $results = $controller->get_precheck_results();
236             // If errors are found then delete the file we created.
237             if (!empty($results['errors'])) {
238                 fulldelete($fulltempdir);
240                 echo $OUTPUT->header();
241                 $backuprenderer = $PAGE->get_renderer('core', 'backup');
242                 echo $backuprenderer->precheck_notices($results);
243                 echo $OUTPUT->continue_button(new \moodle_url('/course/view.php', array('id' => $this->_courseid)));
244                 echo $OUTPUT->footer();
245                 exit();
246             }
247         }
249         // Run the import.
250         $controller->execute_plan();
252         // Have finished with the controller, let's destroy it, freeing mem and resources.
253         $controller->destroy();
255         // Fire event.
256         $event = \tool_recyclebin\event\course_bin_item_restored::create(array(
257             'objectid' => $item->id,
258             'context' => $context
259         ));
260         $event->add_record_snapshot('tool_recyclebin_course', $item);
261         $event->trigger();
263         // Cleanup.
264         fulldelete($fulltempdir);
265         $this->delete_item($item);
266     }
268     /**
269      * Delete an item from the recycle bin.
270      *
271      * @param \stdClass $item The item database record
272      */
273     public function delete_item($item) {
274         global $DB;
276         // Grab the course context.
277         $context = \context_course::instance($this->_courseid);
279         // Delete the files.
280         $fs = get_file_storage();
281         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id);
282         foreach ($files as $file) {
283             $file->delete();
284         }
286         // Delete the record.
287         $DB->delete_records('tool_recyclebin_course', array(
288             'id' => $item->id
289         ));
291         // The course might have been deleted, check we have a context.
292         $context = \context_course::instance($item->courseid, \IGNORE_MISSING);
293         if (!$context) {
294             return;
295         }
297         // Fire event.
298         $event = \tool_recyclebin\event\course_bin_item_deleted::create(array(
299             'objectid' => $item->id,
300             'context' => $context
301         ));
302         $event->add_record_snapshot('tool_recyclebin_course', $item);
303         $event->trigger();
304     }
306     /**
307      * Can we view items in this recycle bin?
308      *
309      * @return bool returns true if they can view, false if not
310      */
311     public function can_view() {
312         $context = \context_course::instance($this->_courseid);
313         return has_capability('tool/recyclebin:viewitems', $context);
314     }
316     /**
317      * Can we restore items in this recycle bin?
318      *
319      * @return bool returns true if they can restore, false if not
320      */
321     public function can_restore() {
322         $context = \context_course::instance($this->_courseid);
323         return has_capability('tool/recyclebin:restoreitems', $context);
324     }
326     /**
327      * Can we delete this?
328      *
329      * @return bool returns true if they can delete, false if not
330      */
331     public function can_delete() {
332         $context = \context_course::instance($this->_courseid);
333         return has_capability('tool/recyclebin:deleteitems', $context);
334     }