Differences Between: [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
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/>. 16 17 /** 18 * This file contains the base classes for portfolio plugins to inherit from: 19 * 20 * portfolio_plugin_pull_base and portfolio_plugin_push_base 21 * which both in turn inherit from portfolio_plugin_base. 22 * {@link http://docs.moodle.org/dev/Writing_a_Portfolio_Plugin} 23 * 24 * @package core_portfolio 25 * @copyright 2008 Penny Leach <penny@catalyst.net.nz>, 26 * Martin Dougiamas <http://dougiamas.com> 27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 */ 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 /** 33 * The base class for portfolio plugins. 34 * 35 * All plugins must subclass this 36 * either via portfolio_plugin_pull_base or portfolio_plugin_push_base 37 * @see portfolio_plugin_pull_base 38 * @see portfolio_plugin_push_base 39 * 40 * @package core_portfolio 41 * @category portfolio 42 * @copyright 2008 Penny Leach <penny@catalyst.net.nz> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 abstract class portfolio_plugin_base { 46 47 /** @var bool whether this object needs writing out to the database */ 48 protected $dirty; 49 50 /** @var integer id of instance */ 51 protected $id; 52 53 /** @var string name of instance */ 54 protected $name; 55 56 /** @var string plugin this instance belongs to */ 57 protected $plugin; 58 59 /** @var bool whether this instance is visible or not */ 60 protected $visible; 61 62 /** @var array admin configured config use {@link set_config} and {@get_config} to access */ 63 protected $config; 64 65 /** @var array user config cache. keyed on userid and then on config field => value use {@link get_user_config} and {@link set_user_config} to access. */ 66 protected $userconfig; 67 68 /** @var array export config during export use {@link get_export_config} and {@link set export_config} to access. */ 69 protected $exportconfig; 70 71 /** @var stdClass user currently exporting data */ 72 protected $user; 73 74 /** @var stdClass a reference to the exporter object */ 75 protected $exporter; 76 77 /** 78 * Array of formats this portfolio supports 79 * the intersection of what this function returns 80 * and what the caller supports will be used. 81 * Use the constants PORTFOLIO_FORMAT_* 82 * 83 * @return array list of formats 84 */ 85 public function supported_formats() { 86 return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICH); 87 } 88 89 /** 90 * Override this if you are supporting the 'file' type (or a subformat) 91 * but have restrictions on mimetypes 92 * 93 * @param string $mimetype file type or subformat 94 * @return bool 95 */ 96 public static function file_mime_check($mimetype) { 97 return true; 98 } 99 100 101 /** 102 * How long does this reasonably expect to take.. 103 * Should we offer the user the option to wait.. 104 * This is deliberately nonstatic so it can take filesize into account 105 * 106 * @param string $callertime - what the caller thinks 107 * the portfolio plugin instance 108 * is given the final say 109 * because it might be (for example) download. 110 */ 111 public abstract function expected_time($callertime); 112 113 /** 114 * Is this plugin push or pull. 115 * If push, cleanup will be called directly after send_package 116 * If not, cleanup will be called after portfolio/file.php is requested 117 */ 118 public abstract function is_push(); 119 120 /** 121 * Returns the user-friendly name for this plugin. 122 * Usually just get_string('pluginname', 'portfolio_something') 123 */ 124 public static function get_name() { 125 throw new coding_exception('get_name() method needs to be overridden in each subclass of portfolio_plugin_base'); 126 } 127 128 /** 129 * Check sanity of plugin. 130 * If this function returns something non empty, ALL instances of your plugin 131 * will be set to invisble and not be able to be set back until it's fixed 132 * 133 * @return string|int|bool - string = error string KEY (must be inside portfolio_$yourplugin) or 0/false if you're ok 134 */ 135 public static function plugin_sanity_check() { 136 return 0; 137 } 138 139 /** 140 * Check sanity of instances. 141 * If this function returns something non empty, the instance will be 142 * set to invislbe and not be able to be set back until it's fixed. 143 * 144 * @return int|string|bool - string = error string KEY (must be inside portfolio_$yourplugin) or 0/false if you're ok 145 */ 146 public function instance_sanity_check() { 147 return 0; 148 } 149 150 /** 151 * Does this plugin need any configuration by the administrator? 152 * If you override this to return true, 153 * you <b>must</b> implement admin_config_form. 154 * @see admin_config_form 155 * 156 * @return bool 157 */ 158 public static function has_admin_config() { 159 return false; 160 } 161 162 /** 163 * Can this plugin be configured by the user in their profile? 164 * If you override this to return true, 165 * you <b>must</b> implement user_config_form 166 * @see user_config_form 167 * 168 * @return bool 169 */ 170 public function has_user_config() { 171 return false; 172 } 173 174 /** 175 * Does this plugin need configuration during export time? 176 * If you override this to return true, 177 * you <b>must</b> implement export_config_form. 178 * @see export_config_form 179 * 180 * @return bool 181 */ 182 public function has_export_config() { 183 return false; 184 } 185 186 /** 187 * Just like the moodle form validation function. 188 * This is passed in the data array from the form 189 * and if a non empty array is returned, form processing will stop. 190 * 191 * @param array $data data from form. 192 */ 193 public function export_config_validation(array $data) {} 194 195 /** 196 * Just like the moodle form validation function. 197 * This is passed in the data array from the form 198 * and if a non empty array is returned, form processing will stop. 199 * 200 * @param array $data data from form. 201 */ 202 public function user_config_validation(array $data) {} 203 204 /** 205 * Sets the export time config from the moodle form. 206 * You can also use this to set export config that 207 * isn't actually controlled by the user. 208 * Eg: things that your subclasses want to keep in state 209 * across the export. 210 * Keys must be in get_allowed_export_config 211 * This is deliberately not final (see boxnet plugin) 212 * @see get_allowed_export_config 213 * 214 * @param array $config named array of config items to set. 215 */ 216 public function set_export_config($config) { 217 $allowed = array_merge( 218 array('wait', 'hidewait', 'format', 'hideformat'), 219 $this->get_allowed_export_config() 220 ); 221 foreach ($config as $key => $value) { 222 if (!in_array($key, $allowed)) { 223 $a = (object)array('property' => $key, 'class' => get_class($this)); 224 throw new portfolio_export_exception($this->get('exporter'), 'invalidexportproperty', 'portfolio', null, $a); 225 } 226 $this->exportconfig[$key] = $value; 227 } 228 } 229 230 /** 231 * Gets an export time config value. 232 * Subclasses should not override this. 233 * 234 * @param string $key field to fetch 235 * @return null|string config value 236 */ 237 public final function get_export_config($key) { 238 $allowed = array_merge( 239 array('hidewait', 'wait', 'format', 'hideformat'), 240 $this->get_allowed_export_config() 241 ); 242 if (!in_array($key, $allowed)) { 243 $a = (object)array('property' => $key, 'class' => get_class($this)); 244 throw new portfolio_export_exception($this->get('exporter'), 'invalidexportproperty', 'portfolio', null, $a); 245 } 246 if (!array_key_exists($key, $this->exportconfig)) { 247 return null; 248 } 249 return $this->exportconfig[$key]; 250 } 251 252 /** 253 * After the user submits their config, 254 * they're given a confirm screen 255 * summarising what they've chosen. 256 * This function should return a table of nice strings => values 257 * of what they've chosen 258 * to be displayed in a table. 259 * 260 * @return bool 261 */ 262 public function get_export_summary() { 263 return false; 264 } 265 266 /** 267 * Called after the caller has finished having control 268 * of its prepare_package function. 269 * This function should read all the files from the portfolio 270 * working file area and zip them and send them or whatever it wants. 271 * get_tempfiles to get the list of files. 272 * @see get_tempfiles 273 * 274 */ 275 public abstract function prepare_package(); 276 277 /** 278 * This is the function that is responsible for sending 279 * the package to the remote system, 280 * or whatever request is necessary to initiate the transfer. 281 * 282 * @return bool success 283 */ 284 public abstract function send_package(); 285 286 287 /** 288 * Once everything is done and the user 289 * has the finish page displayed to them. 290 * The base class takes care of printing them 291 * "return to where you are" or "continue to portfolio" links. 292 * This function allows for exta finish options from the plugin 293 * 294 * @return bool 295 */ 296 public function get_extra_finish_options() { 297 return false; 298 } 299 300 /** 301 * The url for the user to continue to their portfolio 302 * during the lifecycle of the request 303 */ 304 public abstract function get_interactive_continue_url(); 305 306 /** 307 * The url to save in the log as the continue url. 308 * This is passed through resolve_static_continue_url() 309 * at display time to the user. 310 * 311 * @return string 312 */ 313 public function get_static_continue_url() { 314 return $this->get_interactive_continue_url(); 315 } 316 317 /** 318 * Override this function if you need to add something on to the url 319 * for post-export continues (eg from the log page). 320 * Mahara does this, for example, to start a jump session. 321 * 322 * @param string $url static continue url 323 * @return string 324 */ 325 public function resolve_static_continue_url($url) { 326 return $url; 327 } 328 329 /** 330 * mform to display to the user in their profile 331 * if your plugin can't be configured by the user, 332 * @see has_user_config. 333 * Don't bother overriding this function 334 * 335 * @param moodleform $mform passed by reference, add elements to it 336 */ 337 public function user_config_form(&$mform) {} 338 339 /** 340 * mform to display to the admin configuring the plugin. 341 * If your plugin can't be configured by the admin, 342 * @see has_admin_config 343 * Don't bother overriding this function. 344 * This function can be called statically or non statically, 345 * depending on whether it's creating a new instance (statically), 346 * or editing an existing one (non statically) 347 * 348 * @param moodleform $mform passed by reference, add elements to it. 349 */ 350 public static function admin_config_form(&$mform) {} 351 352 /** 353 * Just like the moodle form validation function, 354 * this is passed in the data array from the form 355 * and if a non empty array is returned, form processing will stop. 356 * 357 * @param array $data data from form. 358 */ 359 public static function admin_config_validation($data) {} 360 361 /** 362 * mform to display to the user exporting data using this plugin. 363 * If your plugin doesn't need user input at this time, 364 * @see has_export_config. 365 * Don't bother overrideing this function 366 * 367 * @param moodleform $mform passed by reference, add elements to it. 368 */ 369 public function export_config_form(&$mform) {} 370 371 /** 372 * Override this if your plugin doesn't allow multiple instances 373 * 374 * @return bool 375 */ 376 public static function allows_multiple_instances() { 377 return true; 378 } 379 380 /** 381 * If at any point the caller wants to steal control, 382 * it can, by returning something that isn't false 383 * in this function 384 * The controller will redirect to whatever url 385 * this function returns. 386 * Afterwards, you can redirect back to portfolio/add.php?postcontrol=1 387 * and post_control is called before the rest of the processing 388 * for the stage is done, 389 * @see post_control 390 * 391 * @param int $stage to steal control *before* (see constants PARAM_STAGE_*} 392 * @return bool 393 */ 394 public function steal_control($stage) { 395 return false; 396 } 397 398 /** 399 * After a plugin has elected to steal control, 400 * and control returns to portfolio/add.php|postcontrol=1, 401 * this function is called, and passed the stage that was stolen control from 402 * and the request (get and post but not cookie) parameters. 403 * This is useful for external systems that need to redirect the user back 404 * with some extra data in the url (like auth tokens etc) 405 * for an example implementation, see boxnet portfolio plugin. 406 * 407 * @param int $stage the stage before control was stolen 408 * @param array $params a merge of $_GET and $_POST 409 */ 410 public function post_control($stage, $params) { } 411 412 /** 413 * This function creates a new instance of a plugin 414 * saves it in the database, saves the config 415 * and returns it. 416 * You shouldn't need to override it 417 * unless you're doing something really funky 418 * 419 * @param string $plugin portfolio plugin to create 420 * @param string $name name of new instance 421 * @param array $config what the admin config form returned 422 * @return object subclass of portfolio_plugin_base 423 */ 424 public static function create_instance($plugin, $name, $config) { 425 global $DB, $CFG; 426 $new = (object)array( 427 'plugin' => $plugin, 428 'name' => $name, 429 ); 430 if (!portfolio_static_function($plugin, 'allows_multiple_instances')) { 431 // check we don't have one already 432 if ($DB->record_exists('portfolio_instance', array('plugin' => $plugin))) { 433 throw new portfolio_exception('multipleinstancesdisallowed', 'portfolio', '', $plugin); 434 } 435 } 436 $newid = $DB->insert_record('portfolio_instance', $new); 437 require_once($CFG->dirroot . '/portfolio/' . $plugin . '/lib.php'); 438 $classname = 'portfolio_plugin_' . $plugin; 439 $obj = new $classname($newid); 440 $obj->set_config($config); 441 $obj->save(); 442 return $obj; 443 } 444 445 /** 446 * Construct a plugin instance. 447 * Subclasses should not need to override this unless they're doing something special 448 * and should call parent::__construct afterwards. 449 * 450 * @param int $instanceid id of plugin instance to construct 451 * @param mixed $record stdclass object or named array - use this if you already have the record to avoid another query 452 * @return portfolio_plugin_base 453 */ 454 public function __construct($instanceid, $record=null) { 455 global $DB; 456 if (!$record) { 457 if (!$record = $DB->get_record('portfolio_instance', array('id' => $instanceid))) { 458 throw new portfolio_exception('invalidinstance', 'portfolio'); 459 } 460 } 461 foreach ((array)$record as $key =>$value) { 462 if (property_exists($this, $key)) { 463 $this->{$key} = $value; 464 } 465 } 466 $this->config = new StdClass; 467 $this->userconfig = array(); 468 $this->exportconfig = array(); 469 foreach ($DB->get_records('portfolio_instance_config', array('instance' => $instanceid)) as $config) { 470 $this->config->{$config->name} = $config->value; 471 } 472 $this->init(); 473 return $this; 474 } 475 476 /** 477 * Called after __construct - allows plugins to perform initialisation tasks 478 * without having to override the constructor. 479 */ 480 protected function init() { } 481 482 /** 483 * A list of fields that can be configured per instance. 484 * This is used for the save handlers of the config form 485 * and as checks in set_config and get_config. 486 * 487 * @return array array of strings (config item names) 488 */ 489 public static function get_allowed_config() { 490 return array(); 491 } 492 493 /** 494 * A list of fields that can be configured by the user. 495 * This is used for the save handlers in the config form 496 * and as checks in set_user_config and get_user_config. 497 * 498 * @return array array of strings (config field names) 499 */ 500 public function get_allowed_user_config() { 501 return array(); 502 } 503 504 /** 505 * A list of fields that can be configured by the user. 506 * This is used for the save handlers in the config form 507 * and as checks in set_export_config and get_export_config. 508 * 509 * @return array array of strings (config field names) 510 */ 511 public function get_allowed_export_config() { 512 return array(); 513 } 514 515 /** 516 * Saves (or updates) the config stored in portfolio_instance_config. 517 * You shouldn't need to override this unless you're doing something funky. 518 * 519 * @param array $config array of config items. 520 */ 521 public final function set_config($config) { 522 global $DB; 523 foreach ($config as $key => $value) { 524 // try set it in $this first 525 try { 526 $this->set($key, $value); 527 continue; 528 } catch (portfolio_exception $e) { } 529 if (!in_array($key, $this->get_allowed_config())) { 530 $a = (object)array('property' => $key, 'class' => get_class($this)); 531 throw new portfolio_export_exception($this->get('exporter'), 'invalidconfigproperty', 'portfolio', null, $a); 532 } 533 if (!isset($this->config->{$key})) { 534 $DB->insert_record('portfolio_instance_config', (object)array( 535 'instance' => $this->id, 536 'name' => $key, 537 'value' => $value, 538 )); 539 } else if ($this->config->{$key} != $value) { 540 $DB->set_field('portfolio_instance_config', 'value', $value, array('name' => $key, 'instance' => $this->id)); 541 } 542 $this->config->{$key} = $value; 543 } 544 } 545 546 /** 547 * Gets the value of a particular config item 548 * 549 * @param string $key key to fetch 550 * @return null|mixed the corresponding value 551 */ 552 public final function get_config($key) { 553 if (!in_array($key, $this->get_allowed_config())) { 554 $a = (object)array('property' => $key, 'class' => get_class($this)); 555 throw new portfolio_export_exception($this->get('exporter'), 'invalidconfigproperty', 'portfolio', null, $a); 556 } 557 if (isset($this->config->{$key})) { 558 return $this->config->{$key}; 559 } 560 return null; 561 } 562 563 /** 564 * Get the value of a config item for a particular user. 565 * 566 * @param string $key key to fetch 567 * @param int $userid id of user (defaults to current) 568 * @return string the corresponding value 569 * 570 */ 571 public final function get_user_config($key, $userid=0) { 572 global $DB; 573 574 if (empty($userid)) { 575 $userid = $this->user->id; 576 } 577 578 if ($key != 'visible') { // handled by the parent class 579 if (!in_array($key, $this->get_allowed_user_config())) { 580 $a = (object)array('property' => $key, 'class' => get_class($this)); 581 throw new portfolio_export_exception($this->get('exporter'), 'invaliduserproperty', 'portfolio', null, $a); 582 } 583 } 584 if (!array_key_exists($userid, $this->userconfig)) { 585 $this->userconfig[$userid] = (object)array_fill_keys(array_merge(array('visible'), $this->get_allowed_user_config()), null); 586 foreach ($DB->get_records('portfolio_instance_user', array('instance' => $this->id, 'userid' => $userid)) as $config) { 587 $this->userconfig[$userid]->{$config->name} = $config->value; 588 } 589 } 590 if ($this->userconfig[$userid]->visible === null) { 591 $this->set_user_config(array('visible' => 1), $userid); 592 } 593 return $this->userconfig[$userid]->{$key}; 594 595 } 596 597 /** 598 * Sets config options for a given user. 599 * 600 * @param array $config array containing key/value pairs to set 601 * @param int $userid userid to set config for (defaults to current) 602 * 603 */ 604 public final function set_user_config($config, $userid=0) { 605 global $DB; 606 607 if (empty($userid)) { 608 $userid = $this->user->id; 609 } 610 611 foreach ($config as $key => $value) { 612 if ($key != 'visible' && !in_array($key, $this->get_allowed_user_config())) { 613 $a = (object)array('property' => $key, 'class' => get_class($this)); 614 throw new portfolio_export_exception($this->get('exporter'), 'invaliduserproperty', 'portfolio', null, $a); 615 } 616 if (!$existing = $DB->get_record('portfolio_instance_user', array('instance'=> $this->id, 'userid' => $userid, 'name' => $key))) { 617 $DB->insert_record('portfolio_instance_user', (object)array( 618 'instance' => $this->id, 619 'name' => $key, 620 'value' => $value, 621 'userid' => $userid, 622 )); 623 } else if ($existing->value != $value) { 624 $DB->set_field('portfolio_instance_user', 'value', $value, array('name' => $key, 'instance' => $this->id, 'userid' => $userid)); 625 } 626 $this->userconfig[$userid]->{$key} = $value; 627 } 628 629 } 630 631 /** 632 * Generic getter for properties belonging to this instance 633 * <b>outside</b> the subclasses 634 * like name, visible etc. 635 * 636 * @param string $field property name 637 * @return array|string|int|boolean value of the field 638 */ 639 public final function get($field) { 640 // This is a legacy change to the way files are get/set. 641 // We now only set $this->file to the id of the \stored_file. So, we need to convert that id back to a \stored_file here. 642 if ($field === 'file') { 643 return $this->get_file(); 644 } 645 if (property_exists($this, $field)) { 646 return $this->{$field}; 647 } 648 $a = (object)array('property' => $field, 'class' => get_class($this)); 649 throw new portfolio_export_exception($this->get('exporter'), 'invalidproperty', 'portfolio', null, $a); 650 } 651 652 /** 653 * Generic setter for properties belonging to this instance 654 * <b>outside</b> the subclass 655 * like name, visible, etc. 656 * 657 * @param string $field property's name 658 * @param string $value property's value 659 * @return bool 660 */ 661 public final function set($field, $value) { 662 // This is a legacy change to the way files are get/set. 663 // Make sure we never save the \stored_file object. Instead, use the id from $file->get_id() - set_file() does this for us. 664 if ($field === 'file') { 665 $this->set_file($value); 666 return true; 667 } 668 if (property_exists($this, $field)) { 669 $this->{$field} =& $value; 670 $this->dirty = true; 671 return true; 672 } 673 $a = (object)array('property' => $field, 'class' => get_class($this)); 674 if ($this->get('exporter')) { 675 throw new portfolio_export_exception($this->get('exporter'), 'invalidproperty', 'portfolio', null, $a); 676 } 677 throw new portfolio_exception('invalidproperty', 'portfolio', null, $a); // this happens outside export (eg admin settings) 678 679 } 680 681 /** 682 * Saves stuff that's been stored in the object to the database. 683 * You shouldn't need to override this 684 * unless you're doing something really funky. 685 * and if so, call parent::save when you're done. 686 * 687 * @return bool 688 */ 689 public function save() { 690 global $DB; 691 if (!$this->dirty) { 692 return true; 693 } 694 $fordb = new StdClass(); 695 foreach (array('id', 'name', 'plugin', 'visible') as $field) { 696 $fordb->{$field} = $this->{$field}; 697 } 698 $DB->update_record('portfolio_instance', $fordb); 699 $this->dirty = false; 700 return true; 701 } 702 703 /** 704 * Deletes everything from the database about this plugin instance. 705 * You shouldn't need to override this unless you're storing stuff 706 * in your own tables. and if so, call parent::delete when you're done. 707 * 708 * @return bool 709 */ 710 public function delete() { 711 global $DB; 712 $DB->delete_records('portfolio_instance_config', array('instance' => $this->get('id'))); 713 $DB->delete_records('portfolio_instance_user', array('instance' => $this->get('id'))); 714 $DB->delete_records('portfolio_tempdata', array('instance' => $this->get('id'))); 715 $DB->delete_records('portfolio_instance', array('id' => $this->get('id'))); 716 $this->dirty = false; 717 return true; 718 } 719 720 /** 721 * Perform any required cleanup functions 722 * 723 * @return bool 724 */ 725 public function cleanup() { 726 return true; 727 } 728 729 /** 730 * Whether this plugin supports multiple exports in the same session 731 * most plugins should handle this, but some that require a redirect for authentication 732 * and then don't support dynamically constructed urls to return to (eg box.net) 733 * need to override this to return false. 734 * This means that moodle will prevent multiple exports of this *type* of plugin 735 * occurring in the same session. 736 * 737 * @return bool 738 */ 739 public static function allows_multiple_exports() { 740 return true; 741 } 742 743 /** 744 * Return a string to put at the header summarising this export 745 * by default, just the plugin instance name 746 * 747 * @return string 748 */ 749 public function heading_summary() { 750 return get_string('exportingcontentto', 'portfolio', $this->name); 751 } 752 } 753 754 /** 755 * Class to inherit from for 'push' type plugins 756 * 757 * Eg: those that send the file via a HTTP post or whatever 758 * 759 * @package core_portfolio 760 * @category portfolio 761 * @copyright 2008 Penny Leach <penny@catalyst.net.nz> 762 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 763 */ 764 abstract class portfolio_plugin_push_base extends portfolio_plugin_base { 765 766 /** 767 * Get the capability to push 768 * 769 * @return bool 770 */ 771 public function is_push() { 772 return true; 773 } 774 } 775 776 /** 777 * Class to inherit from for 'pull' type plugins. 778 * 779 * Eg: those that write a file and wait for the remote system to request it 780 * from portfolio/file.php. 781 * If you're using this you must do $this->set('file', $file) so that it can be served. 782 * 783 * @package core_portfolio 784 * @category portfolio 785 * @copyright 2008 Penny Leach <penny@catalyst.net.nz> 786 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 787 */ 788 abstract class portfolio_plugin_pull_base extends portfolio_plugin_base { 789 790 /** @var int $file the id of a single file */ 791 protected $file; 792 793 /** 794 * return the enablelity to push 795 * 796 * @return bool 797 */ 798 public function is_push() { 799 return false; 800 } 801 802 /** 803 * The base part of the download file url to pull files from 804 * your plugin might need to add &foo=bar on the end 805 * @see verify_file_request_params 806 * 807 * @return string the url 808 */ 809 public function get_base_file_url() { 810 global $CFG; 811 return $CFG->wwwroot . '/portfolio/file.php?id=' . $this->exporter->get('id'); 812 } 813 814 /** 815 * Before sending the file when the pull is requested, verify the request parameters. 816 * These might include a token of some sort of whatever 817 * 818 * @param array $params request parameters (POST wins over GET) 819 */ 820 public abstract function verify_file_request_params($params); 821 822 /** 823 * Called from portfolio/file.php. 824 * This function sends the stored file out to the browser. 825 * The default is to just use send_stored_file, 826 * but other implementations might do something different, 827 * for example, send back the file base64 encoded and encrypted 828 * mahara does this but in the response to an xmlrpc request 829 * rather than through file.php 830 */ 831 public function send_file() { 832 $file = $this->get('file'); 833 if (!($file instanceof stored_file)) { 834 throw new portfolio_export_exception($this->get('exporter'), 'filenotfound', 'portfolio'); 835 } 836 // don't die(); afterwards, so we can clean up. 837 send_stored_file($file, 0, 0, true, array('dontdie' => true)); 838 $this->get('exporter')->log_transfer(); 839 } 840 841 /** 842 * Sets the $file instance var to the id of the supplied \stored_file. 843 844 * This helper allows the $this->get('file') call to return a \stored_file, but means that we only ever record an id reference 845 * in the $file instance var. 846 * 847 * @param \stored_file $file The stored_file instance. 848 * @return void 849 */ 850 protected function set_file(\stored_file $file) { 851 $fileid = $file->get_id(); 852 if (empty($fileid)) { 853 debugging('stored_file->id should not be empty'); 854 $this->file = null; 855 } else { 856 $this->file = $fileid; 857 } 858 } 859 860 /** 861 * Gets the \stored_file object from the file id in the $file instance var. 862 * 863 * @return stored_file|null the \stored_file object if it exists, null otherwise. 864 */ 865 protected function get_file() { 866 if (!$this->file) { 867 return null; 868 } 869 // The get_file_by_id call can return false, so normalise to null. 870 $file = get_file_storage()->get_file_by_id($this->file); 871 return ($file) ? $file : null; 872 } 873 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body