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