[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/data/ -> locallib.php (source)

   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * @package   mod_data
  20   * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  require_once($CFG->dirroot . '/mod/data/lib.php');
  25  require_once($CFG->libdir . '/portfolio/caller.php');
  26  require_once($CFG->libdir . '/filelib.php');
  27  
  28  /**
  29   * The class to handle entry exports of a database module
  30   */
  31  class data_portfolio_caller extends portfolio_module_caller_base {
  32  
  33      /** @var int the single record to export */
  34      protected $recordid;
  35  
  36      /** @var object the record from the data table */
  37      private $data;
  38  
  39      /**#@+ @var array the fields used and their fieldtypes */
  40      private $fields;
  41      private $fieldtypes;
  42  
  43      /** @var object the records to export */
  44      private $records;
  45  
  46      /** @var int how many records are 'mine' */
  47      private $minecount;
  48  
  49      /**
  50       * the required callback arguments for a single-record export
  51       *
  52       * @return array
  53       */
  54      public static function expected_callbackargs() {
  55          return array(
  56              'id'       => true,
  57              'recordid' => false,
  58          );
  59      }
  60  
  61      /**
  62       * @param array $callbackargs the arguments passed through
  63       */
  64      public function __construct($callbackargs) {
  65          parent::__construct($callbackargs);
  66          // set up the list of fields to export
  67          $this->selectedfields = array();
  68          foreach ($callbackargs as $key => $value) {
  69              if (strpos($key, 'field_') === 0) {
  70                  $this->selectedfields[] = substr($key, 6);
  71              }
  72          }
  73      }
  74  
  75      /**
  76       * load up the data needed for the export
  77       *
  78       * @global object $DB
  79       */
  80      public function load_data() {
  81          global $DB, $USER;
  82          if (!$this->cm = get_coursemodule_from_id('data', $this->id)) {
  83              throw new portfolio_caller_exception('invalidid', 'data');
  84          }
  85          if (!$this->data = $DB->get_record('data', array('id' => $this->cm->instance))) {
  86              throw new portfolio_caller_exception('invalidid', 'data');
  87          }
  88          $fieldrecords = $DB->get_records('data_fields', array('dataid' => $this->cm->instance), 'id');
  89          // populate objets for this databases fields
  90          $this->fields = array();
  91          foreach ($fieldrecords as $fieldrecord) {
  92              $tmp = data_get_field($fieldrecord, $this->data);
  93              $this->fields[] = $tmp;
  94              $this->fieldtypes[]  = $tmp->type;
  95          }
  96  
  97          $this->records = array();
  98          if ($this->recordid) {
  99              $tmp = $DB->get_record('data_records', array('id' => $this->recordid));
 100              $tmp->content = $DB->get_records('data_content', array('recordid' => $this->recordid));
 101              $this->records[] = $tmp;
 102          } else {
 103              $where = array('dataid' => $this->data->id);
 104              if (!has_capability('mod/data:exportallentries', context_module::instance($this->cm->id))) {
 105                  $where['userid'] = $USER->id; // get them all in case, we'll unset ones that aren't ours later if necessary
 106              }
 107              $tmp = $DB->get_records('data_records', $where);
 108              foreach ($tmp as $t) {
 109                  $t->content = $DB->get_records('data_content', array('recordid' => $t->id));
 110                  $this->records[] = $t;
 111              }
 112              $this->minecount = $DB->count_records('data_records', array('dataid' => $this->data->id, 'userid' => $USER->id));
 113          }
 114  
 115          if ($this->recordid) {
 116              list($formats, $files) = self::formats($this->fields, $this->records[0]);
 117              $this->set_file_and_format_data($files);
 118          }
 119      }
 120  
 121      /**
 122       * How long we think the export will take
 123       * Single entry is probably not too long.
 124       * But we check for filesizes
 125       * Else base it on the number of records
 126       *
 127       * @return one of PORTFOLIO_TIME_XX constants
 128       */
 129      public function expected_time() {
 130          if ($this->recordid) {
 131              return $this->expected_time_file();
 132          } else {
 133              return portfolio_expected_time_db(count($this->records));
 134          }
 135      }
 136  
 137      /**
 138       * Calculate the shal1 of this export
 139       * Dependent on the export format.
 140       * @return string
 141       */
 142      public function get_sha1() {
 143          // in the case that we're exporting a subclass of 'file' and we have a singlefile,
 144          // then we're not exporting any metadata, just the file by itself by mimetype.
 145          if ($this->exporter->get('format') instanceof portfolio_format_file && $this->singlefile) {
 146              return $this->get_sha1_file();
 147          }
 148          // otherwise we're exporting some sort of multipart content so use the data
 149          $str = '';
 150          foreach ($this->records as $record) {
 151              foreach ($record as $data) {
 152                  if (is_array($data) || is_object($data)) {
 153                      $keys = array_keys($data);
 154                      $testkey = array_pop($keys);
 155                      if (is_array($data[$testkey]) || is_object($data[$testkey])) {
 156                          foreach ($data as $d) {
 157                              $str .= implode(',', (array)$d);
 158                          }
 159                      } else {
 160                          $str .= implode(',', (array)$data);
 161                      }
 162                  } else {
 163                      $str .= $data;
 164                  }
 165              }
 166          }
 167          return sha1($str . ',' . $this->exporter->get('formatclass'));
 168      }
 169  
 170      /**
 171       * Prepare the package for export
 172       *
 173       * @return stored_file object
 174       */
 175      public function prepare_package() {
 176          global $DB;
 177          $leapwriter = null;
 178          $content = '';
 179          $filename = '';
 180          $uid = $this->exporter->get('user')->id;
 181          $users = array(); //cache
 182          $onlymine = $this->get_export_config('mineonly');
 183          if ($this->exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
 184              $leapwriter = $this->exporter->get('format')->leap2a_writer();
 185              $ids = array();
 186          }
 187  
 188          if ($this->exporter->get('format') instanceof portfolio_format_file && $this->singlefile) {
 189              return $this->get('exporter')->copy_existing_file($this->singlefile);
 190          }
 191          foreach ($this->records  as $key => $record) {
 192              if ($onlymine && $record->userid != $uid) {
 193                  unset($this->records[$key]); // sha1
 194                  continue;
 195              }
 196              list($tmpcontent, $files)  = $this->exportentry($record);
 197              $content .= $tmpcontent;
 198              if ($leapwriter) {
 199                  $entry = new portfolio_format_leap2a_entry('dataentry' . $record->id, $this->data->name, 'resource', $tmpcontent);
 200                  $entry->published = $record->timecreated;
 201                  $entry->updated = $record->timemodified;
 202                  if ($record->userid != $uid) {
 203                      if (!array_key_exists($record->userid, $users)) {
 204                          $users[$record->userid] = $DB->get_record('user', array('id' => $record->userid), 'id,firstname,lastname');
 205                      }
 206                      $entry->author = $users[$record->userid];
 207                  }
 208                  $ids[] = $entry->id;
 209                  $leapwriter->link_files($entry, $files, 'dataentry' . $record->id . 'file');
 210                  $leapwriter->add_entry($entry);
 211              }
 212          }
 213          if ($leapwriter) {
 214              if (count($this->records) > 1) { // make a selection element to tie them all together
 215                  $selection = new portfolio_format_leap2a_entry('datadb' . $this->data->id,
 216                      get_string('entries', 'data') . ': ' . $this->data->name, 'selection');
 217                  $leapwriter->add_entry($selection);
 218                  $leapwriter->make_selection($selection, $ids, 'Grouping');
 219              }
 220              $filename = $this->exporter->get('format')->manifest_name();
 221              $content = $leapwriter->to_xml();
 222          } else {
 223              if (count($this->records) == 1) {
 224                  $filename = clean_filename($this->cm->name . '-entry.html');
 225              } else {
 226                  $filename = clean_filename($this->cm->name . '-full.html');
 227              }
 228          }
 229          return $this->exporter->write_new_file(
 230              $content,
 231              $filename,
 232              ($this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH) // if we have associate files, this is a 'manifest'
 233          );
 234      }
 235  
 236      /**
 237       * Verify the user can still export this entry
 238       *
 239       * @return bool
 240       */
 241      public function check_permissions() {
 242          if ($this->recordid) {
 243              if (data_isowner($this->recordid)) {
 244                  return has_capability('mod/data:exportownentry', context_module::instance($this->cm->id));
 245              }
 246              return has_capability('mod/data:exportentry', context_module::instance($this->cm->id));
 247          }
 248          if ($this->has_export_config() && !$this->get_export_config('mineonly')) {
 249              return has_capability('mod/data:exportallentries', context_module::instance($this->cm->id));
 250          }
 251          return has_capability('mod/data:exportownentry', context_module::instance($this->cm->id));
 252      }
 253  
 254      /**
 255       *  @return string
 256       */
 257      public static function display_name() {
 258          return get_string('modulename', 'data');
 259      }
 260  
 261      /**
 262       * @global object
 263       * @return bool|void
 264       */
 265      public function __wakeup() {
 266          global $CFG;
 267          if (empty($CFG)) {
 268              return true; // too early yet
 269          }
 270          foreach ($this->fieldtypes as $key => $field) {
 271              require_once($CFG->dirroot . '/mod/data/field/' . $field .'/field.class.php');
 272              $this->fields[$key] = unserialize(serialize($this->fields[$key]));
 273          }
 274      }
 275  
 276      /**
 277       * Prepare a single entry for export, replacing all the content etc
 278       *
 279       * @param stdclass $record the entry to export
 280       *
 281       * @return array with key 0 = the html content, key 1 = array of attachments
 282       */
 283      private function exportentry($record) {
 284      // Replacing tags
 285          $patterns = array();
 286          $replacement = array();
 287  
 288          $files = array();
 289      // Then we generate strings to replace for normal tags
 290          $format = $this->get('exporter')->get('format');
 291          foreach ($this->fields as $field) {
 292              $patterns[]='[['.$field->field->name.']]';
 293              if (is_callable(array($field, 'get_file'))) {
 294                  if (!$file = $field->get_file($record->id)) {
 295                      $replacement[] = '';
 296                      continue; // probably left empty
 297                  }
 298                  $replacement[] = $format->file_output($file);
 299                  $this->get('exporter')->copy_existing_file($file);
 300                  $files[] = $file;
 301              } else {
 302                  $replacement[] = $field->display_browse_field($record->id, 'singletemplate');
 303              }
 304          }
 305  
 306      // Replacing special tags (##Edit##, ##Delete##, ##More##)
 307          $patterns[]='##edit##';
 308          $patterns[]='##delete##';
 309          $patterns[]='##export##';
 310          $patterns[]='##more##';
 311          $patterns[]='##moreurl##';
 312          $patterns[]='##user##';
 313          $patterns[]='##approve##';
 314          $patterns[]='##disapprove##';
 315          $patterns[]='##comments##';
 316          $patterns[] = '##timeadded##';
 317          $patterns[] = '##timemodified##';
 318          $replacement[] = '';
 319          $replacement[] = '';
 320          $replacement[] = '';
 321          $replacement[] = '';
 322          $replacement[] = '';
 323          $replacement[] = '';
 324          $replacement[] = '';
 325          $replacement[] = '';
 326          $replacement[] = '';
 327          $replacement[] = userdate($record->timecreated);
 328          $replacement[] = userdate($record->timemodified);
 329  
 330          // actual replacement of the tags
 331          return array(str_ireplace($patterns, $replacement, $this->data->singletemplate), $files);
 332      }
 333  
 334      /**
 335       * Given the fields being exported, and the single record,
 336       * work out which export format(s) we can use
 337       *
 338       * @param array $fields array of field objects
 339       * @param object $record The data record object
 340       *
 341       * @uses PORTFOLIO_FORMAT_PLAINHTML
 342       * @uses PORTFOLIO_FORMAT_RICHHTML
 343       *
 344       * @return array of PORTFOLIO_XX constants
 345       */
 346      public static function formats($fields, $record) {
 347          $formats = array(PORTFOLIO_FORMAT_PLAINHTML);
 348          $includedfiles = array();
 349          foreach ($fields as $singlefield) {
 350              if (is_callable(array($singlefield, 'get_file'))) {
 351                  if ($file = $singlefield->get_file($record->id)) {
 352                      $includedfiles[] = $file;
 353                  }
 354              }
 355          }
 356          if (count($includedfiles) == 1 && count($fields) == 1) {
 357              $formats = array(portfolio_format_from_mimetype($includedfiles[0]->get_mimetype()));
 358          } else if (count($includedfiles) > 0) {
 359              $formats = array(PORTFOLIO_FORMAT_RICHHTML);
 360          }
 361          return array($formats, $includedfiles);
 362      }
 363  
 364      public static function has_files($data) {
 365          global $DB;
 366          $fieldrecords = $DB->get_records('data_fields', array('dataid' => $data->id), 'id');
 367          // populate objets for this databases fields
 368          foreach ($fieldrecords as $fieldrecord) {
 369              $field = data_get_field($fieldrecord, $data);
 370              if (is_callable(array($field, 'get_file'))) {
 371                  return true;
 372              }
 373          }
 374          return false;
 375      }
 376  
 377      /**
 378       * base supported formats before we know anything about the export
 379       */
 380      public static function base_supported_formats() {
 381          return array(PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_LEAP2A);
 382      }
 383  
 384      public function has_export_config() {
 385          // if we're exporting more than just a single entry,
 386          // and we have the capability to export all entries,
 387          // then ask whether we want just our own, or all of them
 388          return (empty($this->recordid) // multi-entry export
 389              && $this->minecount > 0    // some of them are mine
 390              && $this->minecount != count($this->records) // not all of them are mine
 391              && has_capability('mod/data:exportallentries', context_module::instance($this->cm->id))); // they actually have a choice in the matter
 392      }
 393  
 394      public function export_config_form(&$mform, $instance) {
 395          if (!$this->has_export_config()) {
 396              return;
 397          }
 398          $mform->addElement('selectyesno', 'mineonly', get_string('exportownentries', 'data', (object)array('mine' => $this->minecount, 'all' => count($this->records))));
 399          $mform->setDefault('mineonly', 1);
 400      }
 401  
 402      public function get_allowed_export_config() {
 403          return array('mineonly');
 404      }
 405  }
 406  
 407  
 408  /**
 409   * Class representing the virtual node with all itemids in the file browser
 410   *
 411   * @category  files
 412   * @copyright 2012 David Mudrak <[email protected]>
 413   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 414   */
 415  class data_file_info_container extends file_info {
 416      /** @var file_browser */
 417      protected $browser;
 418      /** @var stdClass */
 419      protected $course;
 420      /** @var stdClass */
 421      protected $cm;
 422      /** @var string */
 423      protected $component;
 424      /** @var stdClass */
 425      protected $context;
 426      /** @var array */
 427      protected $areas;
 428      /** @var string */
 429      protected $filearea;
 430  
 431      /**
 432       * Constructor (in case you did not realize it ;-)
 433       *
 434       * @param file_browser $browser
 435       * @param stdClass $course
 436       * @param stdClass $cm
 437       * @param stdClass $context
 438       * @param array $areas
 439       * @param string $filearea
 440       */
 441      public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
 442          parent::__construct($browser, $context);
 443          $this->browser = $browser;
 444          $this->course = $course;
 445          $this->cm = $cm;
 446          $this->component = 'mod_data';
 447          $this->context = $context;
 448          $this->areas = $areas;
 449          $this->filearea = $filearea;
 450      }
 451  
 452      /**
 453       * @return array with keys contextid, filearea, itemid, filepath and filename
 454       */
 455      public function get_params() {
 456          return array(
 457              'contextid' => $this->context->id,
 458              'component' => $this->component,
 459              'filearea' => $this->filearea,
 460              'itemid' => null,
 461              'filepath' => null,
 462              'filename' => null,
 463          );
 464      }
 465  
 466      /**
 467       * Can new files or directories be added via the file browser
 468       *
 469       * @return bool
 470       */
 471      public function is_writable() {
 472          return false;
 473      }
 474  
 475      /**
 476       * Should this node be considered as a folder in the file browser
 477       *
 478       * @return bool
 479       */
 480      public function is_directory() {
 481          return true;
 482      }
 483  
 484      /**
 485       * Returns localised visible name of this node
 486       *
 487       * @return string
 488       */
 489      public function get_visible_name() {
 490          return $this->areas[$this->filearea];
 491      }
 492  
 493      /**
 494       * Returns list of children nodes
 495       *
 496       * @return array of file_info instances
 497       */
 498      public function get_children() {
 499          return $this->get_filtered_children('*', false, true);
 500      }
 501  
 502      /**
 503       * Help function to return files matching extensions or their count
 504       *
 505       * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 506       * @param bool|int $countonly if false returns the children, if an int returns just the
 507       *    count of children but stops counting when $countonly number of children is reached
 508       * @param bool $returnemptyfolders if true returns items that don't have matching files inside
 509       * @return array|int array of file_info instances or the count
 510       */
 511      private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
 512          global $DB;
 513          $params = array('contextid' => $this->context->id,
 514              'component' => $this->component,
 515              'filearea' => $this->filearea);
 516          $sql = 'SELECT DISTINCT itemid
 517                      FROM {files}
 518                      WHERE contextid = :contextid
 519                      AND component = :component
 520                      AND filearea = :filearea';
 521          if (!$returnemptyfolders) {
 522              $sql .= ' AND filename <> :emptyfilename';
 523              $params['emptyfilename'] = '.';
 524          }
 525          list($sql2, $params2) = $this->build_search_files_sql($extensions);
 526          $sql .= ' '.$sql2;
 527          $params = array_merge($params, $params2);
 528          if ($countonly === false) {
 529              $sql .= ' ORDER BY itemid DESC';
 530          }
 531  
 532          $rs = $DB->get_recordset_sql($sql, $params);
 533          $children = array();
 534          foreach ($rs as $record) {
 535              if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $record->itemid)) {
 536                  $children[] = $child;
 537              }
 538              if ($countonly !== false && count($children) >= $countonly) {
 539                  break;
 540              }
 541          }
 542          $rs->close();
 543          if ($countonly !== false) {
 544              return count($children);
 545          }
 546          return $children;
 547      }
 548  
 549      /**
 550       * Returns list of children which are either files matching the specified extensions
 551       * or folders that contain at least one such file.
 552       *
 553       * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 554       * @return array of file_info instances
 555       */
 556      public function get_non_empty_children($extensions = '*') {
 557          return $this->get_filtered_children($extensions, false);
 558      }
 559  
 560      /**
 561       * Returns the number of children which are either files matching the specified extensions
 562       * or folders containing at least one such file.
 563       *
 564       * @param string|array $extensions, for example '*' or array('.gif','.jpg')
 565       * @param int $limit stop counting after at least $limit non-empty children are found
 566       * @return int
 567       */
 568      public function count_non_empty_children($extensions = '*', $limit = 1) {
 569          return $this->get_filtered_children($extensions, $limit);
 570      }
 571  
 572      /**
 573       * Returns parent file_info instance
 574       *
 575       * @return file_info or null for root
 576       */
 577      public function get_parent() {
 578          return $this->browser->get_file_info($this->context);
 579      }
 580  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1