MDL-14591 - added some phpdocs, moved the transfer log insert into its own method...
[moodle.git] / lib / portfolio / exporter.php
CommitLineData
87fcac8d 1<?php
2/**
3 * Moodle - Modular Object-Oriented Dynamic Learning Environment
4 * http://moodle.org
5 * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * @package moodle
21 * @subpackage portfolio
22 * @author Penny Leach <penny@catalyst.net.nz>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
24 * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
25 *
26 * This file contains the class definition for the exporter object.
27 */
28
29/**
30* The class that handles the various stages of the actual export
31* and the communication between the caller and the portfolio plugin.
32* this is stored in the database between page requests in serialized base64 encoded form
33* also contains helper methods for the plugin and caller to use (at the end of the file)
34* {@see get_base_filearea} - where to write files to
35* {@see write_new_file} - write some content to a file in the export filearea
36* {@see copy_existing_file} - copy an existing file into the export filearea
37* {@see get_tempfiles} - return list of all files in the export filearea
38*/
39class portfolio_exporter {
40
41 /**
42 * the caller object used during the export
43 */
44 private $caller;
45
46 /** the portfolio plugin instanced used during the export
47 */
48 private $instance;
49
50 /**
51 * if there has been no config form displayed to the user
52 */
36b1cfd6 53 private $noexportconfig;
87fcac8d 54
55 /**
56 * the navigation to display on the wizard screens
57 * built from build_navigation
58 */
59 private $navigation;
60
61 /**
62 * the user currently exporting content
63 * always $USER, but more conveniently placed here
64 */
65 private $user;
66
67 /** the file to include that contains the class defintion
68 * of the portfolio instance plugin
69 * used to re-waken the object after sleep
70 */
71 public $instancefile;
72
73 /**
74 * the file to include that contains the class definition
75 * of the caller object
76 * used to re-waken the object after sleep
77 */
78 public $callerfile;
79
80 /**
81 * the current stage of the export
82 */
83 private $stage;
84
85 /**
86 * whether something (usually the portfolio plugin)
87 * has forced queuing
88 */
89 private $forcequeue;
90
91 /**
92 * id of this export
93 * matches record in portfolio_tempdata table
94 * and used for itemid for file storage.
95 */
96 private $id;
97
98 /**
99 * the session key during the export
100 * used to avoid hijacking transfers
101 */
102 private $sesskey;
103
104 /**
105 * array of stages that have had the portfolio plugin already steal control from them
106 */
107 private $alreadystolen;
108
2ddd044a 109 /**
110 * files that the exporter has written to this temp area
111 * keep track of this in case of duplicates within one export
112 * see MDL-16390
113 */
114 private $newfilehashes;
115
87fcac8d 116 /**
117 * construct a new exporter for use
118 *
119 * @param portfolio_plugin_base subclass $instance portfolio instance (passed by reference)
120 * @param portfolio_caller_base subclass $caller portfolio caller (passed by reference)
121 * @param string $callerfile path to callerfile (relative to dataroot)
122 * @param string $navigation result of build_navigation (passed to print_header)
123 */
124 public function __construct(&$instance, &$caller, $callerfile, $navigation) {
125 $this->instance =& $instance;
126 $this->caller =& $caller;
127 if ($instance) {
128 $this->instancefile = 'portfolio/type/' . $instance->get('plugin') . '/lib.php';
129 $this->instance->set('exporter', $this);
130 }
131 $this->callerfile = $callerfile;
132 $this->stage = PORTFOLIO_STAGE_CONFIG;
133 $this->navigation = $navigation;
134 $this->caller->set('exporter', $this);
135 $this->alreadystolen = array();
2ddd044a 136 $this->newfilehashes = array();
87fcac8d 137 }
138
139 /*
140 * generic getter for properties belonging to this instance
141 * <b>outside</b> the subclasses
142 * like name, visible etc.
143 */
144 public function get($field) {
145 if (property_exists($this, $field)) {
146 return $this->{$field};
147 }
148 $a = (object)array('property' => $field, 'class' => get_class($this));
149 throw new portfolio_export_exception($this, 'invalidproperty', 'portfolio', null, $a);
150 }
151
152 /**
153 * generic setter for properties belonging to this instance
154 * <b>outside</b> the subclass
155 * like name, visible, etc.
156 */
157 public function set($field, &$value) {
158 if (property_exists($this, $field)) {
159 $this->{$field} =& $value;
160 if ($field == 'instance') {
161 $this->instancefile = 'portfolio/type/' . $this->instance->get('plugin') . '/lib.php';
162 $this->instance->set('exporter', $this);
163 }
164 $this->dirty = true;
165 return true;
166 }
167 $a = (object)array('property' => $field, 'class' => get_class($this));
168 throw new portfolio_export_exception($this, 'invalidproperty', 'portfolio', null, $a);
169
170 }
171
172 /**
173 * process the given stage calling whatever functions are necessary
174 *
175 * @param int $stage (see PORTFOLIO_STAGE_* constants)
176 * @param boolean $alreadystolen used to avoid letting plugins steal control twice.
177 *
178 * @return boolean whether or not to process the next stage. this is important as the function is called recursively.
179 */
180 public function process_stage($stage, $alreadystolen=false) {
181 $this->set('stage', $stage);
182 if ($alreadystolen) {
183 $this->alreadystolen[$stage] = true;
184 } else {
185 if (!array_key_exists($stage, $this->alreadystolen)) {
186 $this->alreadystolen[$stage] = false;
187 }
188 }
87fcac8d 189 if (!$this->alreadystolen[$stage] && $url = $this->instance->steal_control($stage)) {
2e0c7925 190 $this->save();
87fcac8d 191 redirect($url);
192 break;
2e0c7925 193 } else {
194 $this->save();
87fcac8d 195 }
196
197 $waiting = $this->instance->get_export_config('wait');
198 if ($stage > PORTFOLIO_STAGE_QUEUEORWAIT && empty($waiting)) {
199 $stage = PORTFOLIO_STAGE_FINISHED;
200 }
201 $functionmap = array(
202 PORTFOLIO_STAGE_CONFIG => 'config',
203 PORTFOLIO_STAGE_CONFIRM => 'confirm',
204 PORTFOLIO_STAGE_QUEUEORWAIT => 'queueorwait',
205 PORTFOLIO_STAGE_PACKAGE => 'package',
206 PORTFOLIO_STAGE_CLEANUP => 'cleanup',
207 PORTFOLIO_STAGE_SEND => 'send',
208 PORTFOLIO_STAGE_FINISHED => 'finished'
209 );
210
211 $function = 'process_stage_' . $functionmap[$stage];
212 try {
213 if ($this->$function()) {
214 // if we get through here it means control was returned
215 // as opposed to wanting to stop processing
216 // eg to wait for user input.
217 $this->save();
218 $stage++;
219 return $this->process_stage($stage);
220 } else {
221 $this->save();
222 return false;
223 }
224 } catch (portfolio_caller_exception $e) {
225 portfolio_export_rethrow_exception($this, $e);
226 } catch (portfolio_plugin_exception $e) {
227 portfolio_export_rethrow_exception($this, $e);
228 } catch (portfolio_export_exception $e) {
229 throw $e;
230 } catch (Exception $e) {
231 debugging(get_string('thirdpartyexception', 'portfolio', get_class($e)));
232 portfolio_export_rethrow_exception($this, $e);
233 }
234 }
235
236 /**
237 * helper function to return the portfolio instance
238 *
239 * @return portfolio_plugin_base subclass
240 */
241 public function instance() {
242 return $this->instance;
243 }
244
245 /**
246 * helper function to return the caller object
247 *
248 * @return portfolio_caller_base subclass
249 */
250 public function caller() {
251 return $this->caller;
252 }
253
254 /**
255 * processes the 'config' stage of the export
256 *
257 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
258 */
259 public function process_stage_config() {
260
261 $pluginobj = $callerobj = null;
262 if ($this->instance->has_export_config()) {
263 $pluginobj = $this->instance;
264 }
265 if ($this->caller->has_export_config()) {
266 $callerobj = $this->caller;
267 }
268 $formats = portfolio_supported_formats_intersect($this->caller->supported_formats($this->caller), $this->instance->supported_formats());
269 $expectedtime = $this->instance->expected_time($this->caller->expected_time());
270 if (count($formats) == 0) {
271 // something went wrong, we should not have gotten this far.
272 throw new portfolio_export_exception($this, 'nocommonformats', 'portfolio', null, get_class($this->caller));
273 }
274 // even if neither plugin or caller wants any config, we have to let the user choose their format, and decide to wait.
275 if ($pluginobj || $callerobj || count($formats) > 1 || ($expectedtime != PORTFOLIO_TIME_LOW && $expectedtime != PORTFOLIO_TIME_FORCEQUEUE)) {
276 $customdata = array(
277 'instance' => $this->instance,
278 'plugin' => $pluginobj,
279 'caller' => $callerobj,
280 'userid' => $this->user->id,
281 'formats' => $formats,
282 'expectedtime' => $expectedtime,
283 );
284 $mform = new portfolio_export_form('', $customdata);
285 if ($mform->is_cancelled()){
286 $this->cancel_request();
287 } else if ($fromform = $mform->get_data()){
288 if (!confirm_sesskey()) {
289 throw new portfolio_export_exception($this, 'confirmsesskeybad');
290 }
291 $pluginbits = array();
292 $callerbits = array();
293 foreach ($fromform as $key => $value) {
294 if (strpos($key, 'plugin_') === 0) {
295 $pluginbits[substr($key, 7)] = $value;
296 } else if (strpos($key, 'caller_') === 0) {
297 $callerbits[substr($key, 7)] = $value;
298 }
299 }
300 $callerbits['format'] = $pluginbits['format'] = $fromform->format;
301 $pluginbits['wait'] = $fromform->wait;
302 if ($expectedtime == PORTFOLIO_TIME_LOW) {
303 $pluginbits['wait'] = 1;
304 $pluginbits['hidewait'] = 1;
305 } else if ($expectedtime == PORTFOLIO_TIME_FORCEQUEUE) {
306 $pluginbits['wait'] = 0;
307 $pluginbits['hidewait'] = 1;
308 $this->forcequeue = true;
309 }
310 $callerbits['hideformat'] = $pluginbits['hideformat'] = (count($formats) == 1);
311 $this->caller->set_export_config($callerbits);
312 $this->instance->set_export_config($pluginbits);
313 return true;
314 } else {
315 $this->print_header('configexport');
316 print_simple_box_start();
317 $mform->display();
318 print_simple_box_end();
319 print_footer();
320 return false;;
321 }
322 } else {
323 $this->noexportconfig = true;
324 $format = array_shift($formats);
325 $config = array(
326 'hidewait' => 1,
327 'wait' => (($expectedtime == PORTFOLIO_TIME_LOW) ? 1 : 0),
328 'format' => $format,
329 'hideformat' => 1
330 );
331 $this->instance->set_export_config($config);
332 $this->caller->set_export_config(array('format' => $format, 'hideformat' => 1));
333 if ($expectedtime == PORTFOLIO_TIME_FORCEQUEUE) {
334 $this->forcequeue = true;
335 }
336 return true;
337 // do not break - fall through to confirm
338 }
339 }
340
341 /**
342 * processes the 'confirm' stage of the export
343 *
344 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
345 */
346 public function process_stage_confirm() {
347 global $CFG, $DB;
348
349 $previous = $DB->get_records(
350 'portfolio_log',
351 array(
352 'userid' => $this->user->id,
353 'portfolio' => $this->instance->get('id'),
354 'caller_sha1' => $this->caller->get_sha1(),
355 )
356 );
357 if (isset($this->noexportconfig) && empty($previous)) {
358 return true;
359 }
360 $strconfirm = get_string('confirmexport', 'portfolio');
361 $yesurl = $CFG->wwwroot . '/portfolio/add.php?stage=' . PORTFOLIO_STAGE_QUEUEORWAIT;
362 $nourl = $CFG->wwwroot . '/portfolio/add.php?cancel=1';
363 $this->print_header('confirmexport');
364 print_simple_box_start();
365 print_heading(get_string('confirmsummary', 'portfolio'), '', 4);
366 $mainsummary = array();
367 if (!$this->instance->get_export_config('hideformat')) {
368 $mainsummary[get_string('selectedformat', 'portfolio')] = get_string('format_' . $this->instance->get_export_config('format'), 'portfolio');
369 }
370 if (!$this->instance->get_export_config('hidewait')) {
371 $mainsummary[get_string('selectedwait', 'portfolio')] = get_string(($this->instance->get_export_config('wait') ? 'yes' : 'no'));
372 }
373 if ($previous) {
374 $previousstr = '';
375 foreach ($previous as $row) {
376 $previousstr .= userdate($row->time);
377 if ($row->caller_class != get_class($this->caller)) {
378 require_once($CFG->dirroot . '/' . $row->caller_file);
379 $previousstr .= ' (' . call_user_func(array($row->caller_class, 'display_name')) . ')';
380 }
381 $previousstr .= '<br />';
382 }
383 $mainsummary[get_string('exportedpreviously', 'portfolio')] = $previousstr;
384 }
385 if (!$csummary = $this->caller->get_export_summary()) {
386 $csummary = array();
387 }
388 if (!$isummary = $this->instance->get_export_summary()) {
389 $isummary = array();
390 }
391 $mainsummary = array_merge($mainsummary, $csummary, $isummary);
392 $table = new StdClass;
393 $table->data = array();
394 foreach ($mainsummary as $string => $value) {
395 $table->data[] = array($string, $value);
396 }
397 print_table($table);
398 notice_yesno($strconfirm, $yesurl, $nourl);
399 print_simple_box_end();
400 print_footer();
401 return false;
402 }
403
404 /**
405 * processes the 'queueornext' stage of the export
406 *
407 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
408 */
409 public function process_stage_queueorwait() {
410 global $SESSION;
411 $wait = $this->instance->get_export_config('wait');
412 if (empty($wait)) {
413 events_trigger('portfolio_send', $this->id);
414 unset($SESSION->portfolioexport);
415 return $this->process_stage_finished(true);
416 }
417 return true;
418 }
419
420 /**
421 * processes the 'package' stage of the export
422 *
423 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
424 */
425 public function process_stage_package() {
426 // now we've agreed on a format,
427 // the caller is given control to package it up however it wants
428 // and then the portfolio plugin is given control to do whatever it wants.
37f03ea0 429 try {
430 $this->caller->prepare_package();
431 } catch (portfolio_exception $e) {
432 throw new portfolio_export_exception($this, 'callercouldnotpackage', 'portfolio', null, $e->getMessage());
433 }
434 catch (file_exception $e) {
435 throw new portfolio_export_exception($this, 'callercouldnotpackage', 'portfolio', null, $e->getMessage());
436 }
437 try {
438 $this->instance->prepare_package();
87fcac8d 439 }
37f03ea0 440 catch (portfolio_exception $e) {
441 throw new portfolio_export_exception($this, 'plugincouldnotpackage', 'portfolio', null, $e->getMessage());
442 }
443 catch (file_exception $e) {
444 throw new portfolio_export_exception($this, 'plugincouldnotpackage', 'portfolio', null, $e->getMessage());
87fcac8d 445 }
446 return true;
447 }
448
449 /**
450 * processes the 'cleanup' stage of the export
451 *
452 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
453 */
454 public function process_stage_cleanup($pullok=false) {
455 global $CFG, $DB, $SESSION;
456
457 if (!$pullok && $this->get('instance') && !$this->get('instance')->is_push()) {
458 unset($SESSION->portfolioexport);
459 return true;
460 }
461 if ($this->get('instance')) {
462 // might not be set - before export really starts
463 $this->get('instance')->cleanup();
464 }
465 $DB->delete_records('portfolio_tempdata', array('id' => $this->id));
466 $fs = get_file_storage();
467 $fs->delete_area_files(SYSCONTEXTID, 'portfolio_exporter', $this->id);
468 unset($SESSION->portfolioexport);
469 return true;
470 }
471
472 /**
473 * processes the 'send' stage of the export
474 *
475 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
476 */
477 public function process_stage_send() {
478 // send the file
37f03ea0 479 try {
480 $this->instance->send_package();
481 }
482 catch (portfolio_plugin_exception $e) {
483 // not catching anything more general here. plugins with dependencies on other libraries that throw exceptions should catch and rethrow.
484 // eg curl exception
485 throw new portfolio_export_exception($this, 'failedtosendpackage', 'portfolio', null, $e->getMessage());
87fcac8d 486 }
de01a507 487 // only log push types, pull happens in send_file
488 if ($this->get('instance')->is_push()) {
489 $this->log_transfer();
490 }
491 return true;
492 }
493
494 /**
495 * log the transfer
496 * this should only be called after the file has been sent
497 * either via push, or sent from a pull request.
498 */
499 public function log_transfer() {
87fcac8d 500 global $DB;
501 $l = array(
502 'userid' => $this->user->id,
503 'portfolio' => $this->instance->get('id'),
504 'caller_file' => $this->callerfile,
505 'caller_sha1' => $this->caller->get_sha1(),
506 'caller_class' => get_class($this->caller),
507 'time' => time(),
508 );
509 $DB->insert_record('portfolio_log', $l);
87fcac8d 510 }
511
512 /**
513 * processes the 'finish' stage of the export
514 *
515 * @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
516 */
517 public function process_stage_finished($queued=false) {
518 $returnurl = $this->caller->get_return_url();
519 $continueurl = $this->instance->get_continue_url();
520 $extras = $this->instance->get_extra_finish_options();
521
522 $key = 'exportcomplete';
37f03ea0 523 if ($queued || $this->forcequeue) {
87fcac8d 524 $key = 'exportqueued';
525 if ($this->forcequeue) {
526 $key = 'exportqueuedforced';
527 }
528 }
529 $this->print_header($key, false);
530 if ($returnurl) {
531 echo '<a href="' . $returnurl . '">' . get_string('returntowhereyouwere', 'portfolio') . '</a><br />';
532 }
533 if ($continueurl) {
534 echo '<a href="' . $continueurl . '">' . get_string('continuetoportfolio', 'portfolio') . '</a><br />';
535 }
536 if (is_array($extras)) {
537 foreach ($extras as $link => $string) {
538 echo '<a href="' . $link . '">' . $string . '</a><br />';
539 }
540 }
541 print_footer();
542 return false;
543 }
544
545
546 /**
547 * local print header function to be reused across the export
548 *
549 * @param string $titlestring key for a portfolio language string
550 * @param string $headerstring key for a portfolio language string
551 */
552 public function print_header($headingstr, $summary=true) {
553 $titlestr = get_string('exporting', 'portfolio');
554 $headerstr = get_string('exporting', 'portfolio');
555
556 print_header($titlestr, $headerstr, $this->navigation);
557 print_heading(get_string($headingstr, 'portfolio'));
558
559 if (!$summary) {
560 return;
561 }
562
563 print_simple_box_start();
564 echo $this->caller->heading_summary();
565 print_simple_box_end();
566 }
567
568 /**
569 * cancels a potfolio request and cleans up the tempdata
570 * and redirects the user back to where they started
571 */
572 public function cancel_request() {
573 if (!isset($this)) {
574 return;
575 }
576 $this->process_stage_cleanup(true);
577 redirect($this->caller->get_return_url());
578 exit;
579 }
580
581 /**
582 * writes out the contents of this object and all its data to the portfolio_tempdata table and sets the 'id' field.
583 */
584 public function save() {
585 global $DB;
586 if (empty($this->id)) {
587 $r = (object)array(
588 'data' => base64_encode(serialize($this)),
589 'expirytime' => time() + (60*60*24),
590 'userid' => $this->user->id,
591 );
592 $this->id = $DB->insert_record('portfolio_tempdata', $r);
593 $this->save(); // call again so that id gets added to the save data.
594 } else {
595 $DB->set_field('portfolio_tempdata', 'data', base64_encode(serialize($this)), array('id' => $this->id));
596 }
597 }
598
599 /**
600 * rewakens the data from the database given the id
601 * makes sure to load the required files with the class definitions
602 *
603 * @param int $id id of data
604 *
605 * @return portfolio_exporter
606 */
607 public static function rewaken_object($id) {
608 global $DB, $CFG;
609 require_once($CFG->libdir . '/filelib.php');
610 if (!$data = $DB->get_record('portfolio_tempdata', array('id' => $id))) {
611 throw new portfolio_exception('invalidtempid', 'portfolio');
612 }
613 $exporter = unserialize(base64_decode($data->data));
614 if ($exporter->instancefile) {
615 require_once($CFG->dirroot . '/' . $exporter->instancefile);
616 }
617 require_once($CFG->dirroot . '/' . $exporter->callerfile);
618 $exporter = unserialize(serialize($exporter));
619 return $exporter;
620 }
621
622 /**
623 * helper function to create the beginnings of a file_record object
624 * to create a new file in the portfolio_temporary working directory
625 * use {@see write_new_file} or {@see copy_existing_file} externally
626 *
627 * @param string $name filename of new record
628 */
629 private function new_file_record_base($name) {
630 return (object)array_merge($this->get_base_filearea(), array(
631 'filepath' => '/',
632 'filename' => $name,
633 ));
634 }
635
636 /**
637 * verifies a rewoken object
638 *
639 * checks to make sure it belongs to the same user and session as is currently in use.
640 *
de01a507 641 * @param boolean $readonly if we're reawakening this for a user to just display in the log view, don't verify the sessionkey
642 * when continuing transfers, you must pass false here.
643 *
87fcac8d 644 * @throws portfolio_exception
645 */
de01a507 646 public function verify_rewaken($readonly=false) {
87fcac8d 647 global $USER;
648 if ($this->get('user')->id != $USER->id) {
649 throw new portfolio_exception('notyours', 'portfolio');
650 }
de01a507 651 if (!$readonly && !confirm_sesskey($this->get('sesskey'))) {
87fcac8d 652 throw new portfolio_exception('confirmsesskeybad');
653 }
654 }
655 /**
656 * copies a file from somewhere else in moodle
657 * to the portfolio temporary working directory
658 * associated with this export
659 *
660 * @param $oldfile stored_file object
661 * @return new stored_file object
662 */
663 public function copy_existing_file($oldfile) {
2ddd044a 664 if (array_key_exists($oldfile->get_contenthash(), $this->newfilehashes)) {
665 return $this->newfilehashes[$oldfile->get_contenthash()];
666 }
87fcac8d 667 $fs = get_file_storage();
668 $file_record = $this->new_file_record_base($oldfile->get_filename());
669 try {
2ddd044a 670 $newfile = $fs->create_file_from_storedfile($file_record, $oldfile->get_id());
671 $this->newfilehashes[$newfile->get_contenthash()] = $newfile;
672 return $newfile;
87fcac8d 673 } catch (file_exception $e) {
674 return false;
675 }
676 }
677
678 /**
679 * writes out some content to a file in the
680 * portfolio temporary working directory
681 * associated with this export
682 *
683 * @param string $content content to write
684 * @param string $name filename to use
685 * @return new stored_file object
686 */
687 public function write_new_file($content, $name) {
688 $fs = get_file_storage();
689 $file_record = $this->new_file_record_base($name);
690 return $fs->create_file_from_string($file_record, $content);
691 }
692
de01a507 693 /**
694 * zips all files in the temporary directory
695 *
696 * @param string $filename name of resulting zipfile (optional, defaults to portfolio-export.zip
697 * @param string $filepath subpath in the filearea (optional, defaults to final)
698 *
699 * @return stored_file resulting stored_file object
700 */
37f03ea0 701 public function zip_tempfiles($filename='portfolio-export.zip', $filepath='/final/') {
702 $zipper = new zip_packer();
703
704 list ($contextid, $filearea, $itemid) = array_values($this->get_base_filearea());
705 if ($newfile = $zipper->archive_to_storage($files, $contextid, $filearea, $itemid, $filepath, $filename, $this->user->id)) {
706 return $newfile;
707 }
708 return false;
709
710 }
711
87fcac8d 712 /**
713 * returns an arary of files in the temporary working directory
714 * for this export
715 * always use this instead of the files api directly
716 *
717 * @return array of stored_file objects keyed by name
718 */
719 public function get_tempfiles() {
720 $fs = get_file_storage();
721 $files = $fs->get_area_files(SYSCONTEXTID, 'portfolio_exporter', $this->id, '', false);
722 if (empty($files)) {
723 return array();
724 }
725 $returnfiles = array();
726 foreach ($files as $f) {
727 $returnfiles[$f->get_filename()] = $f;
728 }
729 return $returnfiles;
730 }
731
732 /**
733 * returns the context, filearea, and itemid
734 * parts of a filearea (not filepath) to be used by
735 * plugins if they want to do things like zip up the contents of
736 * the temp area to here, or something that can't be done just using
737 * write_new_file, copy_existing_file or get_tempfiles
738 *
739 * @return array contextid, filearea, itemid are the keys.
740 */
741 public function get_base_filearea() {
742 return array(
743 'contextid' => SYSCONTEXTID,
744 'filearea' => 'portfolio_exporter',
745 'itemid' => $this->id,
746 );
747 }
748
749}
750
751?>