MDL-54205 tool_recyclebin: Adding missing destroy() calls.
[moodle.git] / admin / tool / recyclebin / classes / category_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_COURSECAT_BIN_FILEAREA', 'recyclebin_coursecat');
31 /**
32  * Represents a category'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 category_bin extends base_bin {
40     /**
41      * @var int The category id.
42      */
43     protected $_categoryid;
45     /**
46      * Constructor.
47      *
48      * @param int $categoryid The category id.
49      */
50     public function __construct($categoryid) {
51         $this->_categoryid = $categoryid;
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', 'categorybinenable');
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         $item = $DB->get_record('tool_recyclebin_category', array(
73             'id' => $itemid
74         ), '*', MUST_EXIST);
76         $item->name = get_course_display_name_for_list($item);
78         return $item;
79     }
81     /**
82      * Returns a list of items in the recycle bin for this course.
83      *
84      * @return array the list of items.
85      */
86     public function get_items() {
87         global $DB;
89         $items = $DB->get_records('tool_recyclebin_category', array(
90             'categoryid' => $this->_categoryid
91         ));
93         foreach ($items as $item) {
94             $item->name = get_course_display_name_for_list($item);
95         }
97         return $items;
98     }
100     /**
101      * Store a course in the recycle bin.
102      *
103      * @param \stdClass $course Course
104      * @throws \moodle_exception
105      */
106     public function store_item($course) {
107         global $CFG, $DB;
109         require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
111         // Backup the course.
112         $user = get_admin();
113         $controller = new \backup_controller(
114             \backup::TYPE_1COURSE,
115             $course->id,
116             \backup::FORMAT_MOODLE,
117             \backup::INTERACTIVE_NO,
118             \backup::MODE_GENERAL,
119             $user->id
120         );
121         $controller->execute_plan();
123         // Grab the result.
124         $result = $controller->get_results();
125         if (!isset($result['backup_destination'])) {
126             throw new \moodle_exception('Failed to backup activity prior to deletion.');
127         }
129         // Have finished with the controller, let's destroy it, freeing mem and resources.
130         $controller->destroy();
132         // Grab the filename.
133         $file = $result['backup_destination'];
134         if (!$file->get_contenthash()) {
135             throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).');
136         }
138         // Record the activity, get an ID.
139         $item = new \stdClass();
140         $item->categoryid = $course->category;
141         $item->shortname = $course->shortname;
142         $item->fullname = $course->fullname;
143         $item->timecreated = time();
144         $binid = $DB->insert_record('tool_recyclebin_category', $item);
146         // Create the location we want to copy this file to.
147         $filerecord = array(
148             'contextid' => \context_coursecat::instance($course->category)->id,
149             'component' => 'tool_recyclebin',
150             'filearea' => TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA,
151             'itemid' => $binid,
152             'timemodified' => time()
153         );
155         // Move the file to our own special little place.
156         $fs = get_file_storage();
157         if (!$fs->create_file_from_storedfile($filerecord, $file)) {
158             // Failed, cleanup first.
159             $DB->delete_records('tool_recyclebin_category', array(
160                 'id' => $binid
161             ));
163             throw new \moodle_exception("Failed to copy backup file to recyclebin.");
164         }
166         // Delete the old file.
167         $file->delete();
169         // Fire event.
170         $event = \tool_recyclebin\event\category_bin_item_created::create(array(
171             'objectid' => $binid,
172             'context' => \context_coursecat::instance($course->category)
173         ));
174         $event->trigger();
175     }
177     /**
178      * Restore an item from the recycle bin.
179      *
180      * @param \stdClass $item The item database record
181      * @throws \moodle_exception
182      */
183     public function restore_item($item) {
184         global $CFG, $OUTPUT, $PAGE;
186         require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
187         require_once($CFG->dirroot . '/course/lib.php');
189         $user = get_admin();
191         // Grab the course category context.
192         $context = \context_coursecat::instance($this->_categoryid);
194         // Get the backup file.
195         $fs = get_file_storage();
196         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA, $item->id,
197             'itemid, filepath, filename', false);
199         if (empty($files)) {
200             throw new \moodle_exception('Invalid recycle bin item!');
201         }
203         if (count($files) > 1) {
204             throw new \moodle_exception('Too many files found!');
205         }
207         // Get the backup file.
208         $file = reset($files);
210         // Get a temp directory name and create it.
211         $tempdir = \restore_controller::get_tempdir_name($context->id, $user->id);
212         $fulltempdir = make_temp_directory('/backup/' . $tempdir);
214         // Extract the backup to tmpdir.
215         $fb = get_file_packer('application/vnd.moodle.backup');
216         $fb->extract_to_pathname($file, $fulltempdir);
218         // Build a course.
219         $course = new \stdClass();
220         $course->category = $this->_categoryid;
221         $course->shortname = $item->shortname;
222         $course->fullname = $item->fullname;
223         $course->summary = '';
225         // Create a new course.
226         $course = create_course($course);
227         if (!$course) {
228             throw new \moodle_exception("Could not create course to restore into.");
229         }
231         // Define the import.
232         $controller = new \restore_controller(
233             $tempdir,
234             $course->id,
235             \backup::INTERACTIVE_NO,
236             \backup::MODE_GENERAL,
237             $user->id,
238             \backup::TARGET_NEW_COURSE
239         );
241         // Prechecks.
242         if (!$controller->execute_precheck()) {
243             $results = $controller->get_precheck_results();
245             // Check if errors have been found.
246             if (!empty($results['errors'])) {
247                 // Delete the temporary file we created.
248                 fulldelete($fulltempdir);
250                 // Delete the course we created.
251                 delete_course($course, false);
253                 echo $OUTPUT->header();
254                 $backuprenderer = $PAGE->get_renderer('core', 'backup');
255                 echo $backuprenderer->precheck_notices($results);
256                 echo $OUTPUT->continue_button(new \moodle_url('/course/index.php', array('categoryid' => $this->_categoryid)));
257                 echo $OUTPUT->footer();
258                 exit();
259             }
260         }
262         // Run the import.
263         $controller->execute_plan();
265         // Have finished with the controller, let's destroy it, freeing mem and resources.
266         $controller->destroy();
268         // Fire event.
269         $event = \tool_recyclebin\event\category_bin_item_restored::create(array(
270             'objectid' => $item->id,
271             'context' => $context
272         ));
273         $event->add_record_snapshot('tool_recyclebin_category', $item);
274         $event->trigger();
276         // Cleanup.
277         fulldelete($fulltempdir);
278         $this->delete_item($item);
279     }
281     /**
282      * Delete an item from the recycle bin.
283      *
284      * @param \stdClass $item The item database record
285      * @throws \coding_exception
286      */
287     public function delete_item($item) {
288         global $DB;
290         // Grab the course category context.
291         $context = \context_coursecat::instance($this->_categoryid);
293         // Delete the files.
294         $fs = get_file_storage();
295         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA, $item->id);
296         foreach ($files as $file) {
297             $file->delete();
298         }
300         // Delete the record.
301         $DB->delete_records('tool_recyclebin_category', array(
302             'id' => $item->id
303         ));
305         // Fire event.
306         $event = \tool_recyclebin\event\category_bin_item_deleted::create(array(
307             'objectid' => $item->id,
308             'context' => \context_coursecat::instance($item->categoryid)
309         ));
310         $event->add_record_snapshot('tool_recyclebin_category', $item);
311         $event->trigger();
312     }
314     /**
315      * Can we view items in this recycle bin?
316      *
317      * @return bool returns true if they can view, false if not
318      */
319     public function can_view() {
320         $context = \context_coursecat::instance($this->_categoryid);
321         return has_capability('tool/recyclebin:viewitems', $context);
322     }
324     /**
325      * Can we restore items in this recycle bin?
326      *
327      * @return bool returns true if they can restore, false if not
328      */
329     public function can_restore() {
330         $context = \context_coursecat::instance($this->_categoryid);
331         return has_capability('tool/recyclebin:restoreitems', $context);
332     }
334     /**
335      * Can we delete items in this recycle bin?
336      *
337      * @return bool returns true if they can delete, false if not
338      */
339     public function can_delete() {
340         $context = \context_coursecat::instance($this->_categoryid);
341         return has_capability('tool/recyclebin:deleteitems', $context);
342     }