Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

       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   * File containing the helper class.
      19   *
      20   * @package    tool_uploadcourse
      21   * @copyright  2013 Frédéric Massart
      22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  defined('MOODLE_INTERNAL') || die();
      26  require_once($CFG->libdir . '/coursecatlib.php');
      27  require_once($CFG->dirroot . '/cache/lib.php');
      28  require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
      29  require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
      30  
      31  /**
      32   * Class containing a set of helpers.
      33   *
      34   * @package    tool_uploadcourse
      35   * @copyright  2013 Frédéric Massart
      36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      37   */
      38  class tool_uploadcourse_helper {
      39  
      40      /**
      41       * Generate a shortname based on a template.
      42       *
      43       * @param array|object $data course data.
      44       * @param string $templateshortname template of shortname.
      45       * @return null|string shortname based on the template, or null when an error occured.
      46       */
      47      public static function generate_shortname($data, $templateshortname) {
      48          if (empty($templateshortname) && !is_numeric($templateshortname)) {
      49              return null;
      50          }
      51          if (strpos($templateshortname, '%') === false) {
      52              return $templateshortname;
      53          }
      54  
      55          $course = (object) $data;
      56          $fullname   = isset($course->fullname) ? $course->fullname : '';
      57          $idnumber   = isset($course->idnumber) ? $course->idnumber  : '';
      58  
      59          $callback = partial(array('tool_uploadcourse_helper', 'generate_shortname_callback'), $fullname, $idnumber);
      60          $result = preg_replace_callback('/(?<!%)%([+~-])?(\d)*([fi])/', $callback, $templateshortname);
      61  
      62          if (!is_null($result)) {
      63              $result = clean_param($result, PARAM_TEXT);
      64          }
      65  
      66          if (empty($result) && !is_numeric($result)) {
      67              $result = null;
      68          }
      69  
      70          return $result;
      71      }
      72  
      73      /**
      74       * Callback used when generating a shortname based on a template.
      75       *
      76       * @param string $fullname full name.
      77       * @param string $idnumber ID number.
      78       * @param array $block result from preg_replace_callback.
      79       * @return string
      80       */
      81      public static function generate_shortname_callback($fullname, $idnumber, $block) {
      82          switch ($block[3]) {
      83              case 'f':
      84                  $repl = $fullname;
      85                  break;
      86              case 'i':
      87                  $repl = $idnumber;
      88                  break;
      89              default:
      90                  return $block[0];
      91          }
      92  
      93          switch ($block[1]) {
      94              case '+':
      95                  $repl = core_text::strtoupper($repl);
      96                  break;
      97              case '-':
      98                  $repl = core_text::strtolower($repl);
      99                  break;
     100              case '~':
     101                  $repl = core_text::strtotitle($repl);
     102                  break;
     103          }
     104  
     105          if (!empty($block[2])) {
     106              $repl = core_text::substr($repl, 0, $block[2]);
     107          }
     108  
     109          return $repl;
     110      }
     111  
     112      /**
     113       * Return the available course formats.
     114       *
     115       * @return array
     116       */
     117      public static function get_course_formats() {
     118          return array_keys(core_component::get_plugin_list('format'));
     119      }
     120  
     121      /**
     122       * Extract enrolment data from passed data.
     123       *
     124       * Constructs an array of methods, and their options:
     125       * array(
     126       *     'method1' => array(
     127       *         'option1' => value,
     128       *         'option2' => value
     129       *     ),
     130       *     'method2' => array(
     131       *         'option1' => value,
     132       *         'option2' => value
     133       *     )
     134       * )
     135       *
     136       * @param array $data data to extract the enrolment data from.
     137       * @return array
     138       */
     139      public static function get_enrolment_data($data) {
     140          $enrolmethods = array();
     141          $enroloptions = array();
     142          foreach ($data as $field => $value) {
     143  
     144              // Enrolmnent data.
     145              $matches = array();
     146              if (preg_match('/^enrolment_(\d+)(_(.+))?$/', $field, $matches)) {
     147                  $key = $matches[1];
     148                  if (!isset($enroloptions[$key])) {
     149                      $enroloptions[$key] = array();
     150                  }
     151                  if (empty($matches[3])) {
     152                      $enrolmethods[$key] = $value;
     153                  } else {
     154                      $enroloptions[$key][$matches[3]] = $value;
     155                  }
     156              }
     157          }
     158  
     159          // Combining enrolment methods and their options in a single array.
     160          $enrolmentdata = array();
     161          if (!empty($enrolmethods)) {
     162              $enrolmentplugins = self::get_enrolment_plugins();
     163              foreach ($enrolmethods as $key => $method) {
     164                  if (!array_key_exists($method, $enrolmentplugins)) {
     165                      // Error!
     166                      continue;
     167                  }
     168                  $enrolmentdata[$enrolmethods[$key]] = $enroloptions[$key];
     169              }
     170          }
     171          return $enrolmentdata;
     172      }
     173  
     174      /**
     175       * Return the enrolment plugins.
     176       *
     177       * The result is cached for faster execution.
     178       *
     179       * @return array
     180       */
     181      public static function get_enrolment_plugins() {
     182          $cache = cache::make('tool_uploadcourse', 'helper');
     183          if (($enrol = $cache->get('enrol')) === false) {
     184              $enrol = enrol_get_plugins(false);
     185              $cache->set('enrol', $enrol);
     186          }
     187          return $enrol;
     188      }
     189  
     190      /**
     191       * Get the restore content tempdir.
     192       *
     193       * The tempdir is the sub directory in which the backup has been extracted.
     194       *
     195       * This caches the result for better performance, but $CFG->keeptempdirectoriesonbackup
     196       * needs to be enabled, otherwise the cache is ignored.
     197       *
     198       * @param string $backupfile path to a backup file.
     199       * @param string $shortname shortname of a course.
     200       * @param array $errors will be populated with errors found.
     201       * @return string|false false when the backup couldn't retrieved.
     202       */
     203      public static function get_restore_content_dir($backupfile = null, $shortname = null, &$errors = array()) {
     204          global $CFG, $DB, $USER;
     205  
     206          $cachekey = null;
     207          if (!empty($backupfile)) {
     208              $backupfile = realpath($backupfile);
     209              if (empty($backupfile) || !is_readable($backupfile)) {
     210                  $errors['cannotreadbackupfile'] = new lang_string('cannotreadbackupfile', 'tool_uploadcourse');
     211                  return false;
     212              }
     213              $cachekey = 'backup_path:' . $backupfile;
     214          } else if (!empty($shortname) || is_numeric($shortname)) {
     215              $cachekey = 'backup_sn:' . $shortname;
     216          }
     217  
     218          if (empty($cachekey)) {
     219              return false;
     220          }
     221  
     222          // If $CFG->keeptempdirectoriesonbackup is not set to true, any restore happening would
     223          // automatically delete the backup directory... causing the cache to return an unexisting directory.
     224          $usecache = !empty($CFG->keeptempdirectoriesonbackup);
     225          if ($usecache) {
     226              $cache = cache::make('tool_uploadcourse', 'helper');
     227          }
     228  
     229          // If we don't use the cache, or if we do and not set, or the directory doesn't exist any more.
     230          if (!$usecache || (($backupid = $cache->get($cachekey)) === false || !is_dir("$CFG->tempdir/backup/$backupid"))) {
     231  
     232              // Use null instead of false because it would consider that the cache key has not been set.
     233              $backupid = null;
     234  
     235              if (!empty($backupfile)) {
     236                  // Extracting the backup file.
     237                  $packer = get_file_packer('application/vnd.moodle.backup');
     238                  $backupid = restore_controller::get_tempdir_name(SITEID, $USER->id);
     239                  $path = "$CFG->tempdir/backup/$backupid/";
     240                  $result = $packer->extract_to_pathname($backupfile, $path);
     241                  if (!$result) {
     242                      $errors['invalidbackupfile'] = new lang_string('invalidbackupfile', 'tool_uploadcourse');
     243                  }
     244              } else if (!empty($shortname) || is_numeric($shortname)) {
     245                  // Creating restore from an existing course.
     246                  $courseid = $DB->get_field('course', 'id', array('shortname' => $shortname), IGNORE_MISSING);
     247                  if (!empty($courseid)) {
     248                      $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE,
     249                          backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     250                      $bc->execute_plan();
     251                      $backupid = $bc->get_backupid();
     252                      $bc->destroy();
     253                  } else {
     254                      $errors['coursetorestorefromdoesnotexist'] =
     255                          new lang_string('coursetorestorefromdoesnotexist', 'tool_uploadcourse');
     256                  }
     257              }
     258  
     259              if ($usecache) {
     260                  $cache->set($cachekey, $backupid);
     261              }
     262          }
     263  
     264          if ($backupid === null) {
     265              $backupid = false;
     266          }
     267          return $backupid;
     268      }
     269  
     270      /**
     271       * Return the role IDs.
     272       *
     273       * The result is cached for faster execution.
     274       *
     275       * @return array
     276       */
     277      public static function get_role_ids() {
     278          $cache = cache::make('tool_uploadcourse', 'helper');
     279          if (($roles = $cache->get('roles')) === false) {
     280              $roles = array();
     281              $rolesraw = get_all_roles();
     282              foreach ($rolesraw as $role) {
     283                  $roles[$role->shortname] = $role->id;
     284              }
     285              $cache->set('roles', $roles);
     286          }
     287          return $roles;
     288      }
     289  
     290      /**
     291       * Get the role renaming data from the passed data.
     292       *
     293       * @param array $data data to extract the names from.
     294       * @param array $errors will be populated with errors found.
     295       * @return array where the key is the role_<id>, the value is the new name.
     296       */
     297      public static function get_role_names($data, &$errors = array()) {
     298          $rolenames = array();
     299          $rolesids = self::get_role_ids();
     300          $invalidroles = array();
     301          foreach ($data as $field => $value) {
     302  
     303              $matches = array();
     304              if (preg_match('/^role_(.+)?$/', $field, $matches)) {
     305                  if (!isset($rolesids[$matches[1]])) {
     306                      $invalidroles[] = $matches[1];
     307                      continue;
     308                  }
     309                  $rolenames['role_' . $rolesids[$matches[1]]] = $value;
     310              }
     311  
     312          }
     313  
     314          if (!empty($invalidroles)) {
     315              $errors['invalidroles'] = new lang_string('invalidroles', 'tool_uploadcourse', implode(', ', $invalidroles));
     316          }
     317  
     318          // Roles names.
     319          return $rolenames;
     320      }
     321  
     322      /**
     323       * Helper to increment an ID number.
     324       *
     325       * This first checks if the ID number is in use.
     326       *
     327       * @param string $idnumber ID number to increment.
     328       * @return string new ID number.
     329       */
     330      public static function increment_idnumber($idnumber) {
     331          global $DB;
     332          while ($DB->record_exists('course', array('idnumber' => $idnumber))) {
     333              $matches = array();
     334              if (!preg_match('/(.*?)([0-9]+)$/', $idnumber, $matches)) {
     335                  $newidnumber = $idnumber . '_2';
     336              } else {
     337                  $newidnumber = $matches[1] . ((int) $matches[2] + 1);
     338              }
     339              $idnumber = $newidnumber;
     340          }
     341          return $idnumber;
     342      }
     343  
     344      /**
     345       * Helper to increment a shortname.
     346       *
     347       * This considers that the shortname passed has to be incremented.
     348       *
     349       * @param string $shortname shortname to increment.
     350       * @return string new shortname.
     351       */
     352      public static function increment_shortname($shortname) {
     353          global $DB;
     354          do {
     355              $matches = array();
     356              if (!preg_match('/(.*?)([0-9]+)$/', $shortname, $matches)) {
     357                  $newshortname = $shortname . '_2';
     358              } else {
     359                  $newshortname = $matches[1] . ($matches[2]+1);
     360              }
     361              $shortname = $newshortname;
     362          } while ($DB->record_exists('course', array('shortname' => $shortname)));
     363          return $shortname;
     364      }
     365  
     366      /**
     367       * Resolve a category based on the data passed.
     368       *
     369       * Key accepted are:
     370       * - category, which is supposed to be a category ID.
     371       * - category_idnumber
     372       * - category_path, array of categories from parent to child.
     373       *
     374       * @param array $data to resolve the category from.
     375       * @param array $errors will be populated with errors found.
     376       * @return int category ID.
     377       */
     378      public static function resolve_category($data, &$errors = array()) {
     379          $catid = null;
     380  
     381          if (!empty($data['category'])) {
     382              $category = coursecat::get((int) $data['category'], IGNORE_MISSING);
     383              if (!empty($category) && !empty($category->id)) {
     384                  $catid = $category->id;
     385              } else {
     386                  $errors['couldnotresolvecatgorybyid'] =
     387                      new lang_string('couldnotresolvecatgorybyid', 'tool_uploadcourse');
     388              }
     389          }
     390  
     391          if (empty($catid) && !empty($data['category_idnumber'])) {
     392              $catid = self::resolve_category_by_idnumber($data['category_idnumber']);
     393              if (empty($catid)) {
     394                  $errors['couldnotresolvecatgorybyidnumber'] =
     395                      new lang_string('couldnotresolvecatgorybyidnumber', 'tool_uploadcourse');
     396              }
     397          }
     398          if (empty($catid) && !empty($data['category_path'])) {
     399              $catid = self::resolve_category_by_path(explode(' / ', $data['category_path']));
     400              if (empty($catid)) {
     401                  $errors['couldnotresolvecatgorybypath'] =
     402                      new lang_string('couldnotresolvecatgorybypath', 'tool_uploadcourse');
     403              }
     404          }
     405  
     406          return $catid;
     407      }
     408  
     409      /**
     410       * Resolve a category by ID number.
     411       *
     412       * @param string $idnumber category ID number.
     413       * @return int category ID.
     414       */
     415      public static function resolve_category_by_idnumber($idnumber) {
     416          global $DB;
     417          $cache = cache::make('tool_uploadcourse', 'helper');
     418          $cachekey = 'cat_idn_' . $idnumber;
     419          if (($id = $cache->get($cachekey)) === false) {
     420              $params = array('idnumber' => $idnumber);
     421              $id = $DB->get_field_select('course_categories', 'id', 'idnumber = :idnumber', $params, IGNORE_MISSING);
     422  
     423              // Little hack to be able to differenciate between the cache not set and a category not found.
     424              if ($id === false) {
     425                  $id = -1;
     426              }
     427  
     428              $cache->set($cachekey, $id);
     429          }
     430  
     431          // Little hack to be able to differenciate between the cache not set and a category not found.
     432          if ($id == -1) {
     433              $id = false;
     434          }
     435  
     436          return $id;
     437      }
     438  
     439      /**
     440       * Resolve a category by path.
     441       *
     442       * @param array $path category names indexed from parent to children.
     443       * @return int category ID.
     444       */
     445      public static function resolve_category_by_path(array $path) {
     446          global $DB;
     447          $cache = cache::make('tool_uploadcourse', 'helper');
     448          $cachekey = 'cat_path_' . serialize($path);
     449          if (($id = $cache->get($cachekey)) === false) {
     450              $parent = 0;
     451              $sql = 'name = :name AND parent = :parent';
     452              while ($name = array_shift($path)) {
     453                  $params = array('name' => $name, 'parent' => $parent);
     454                  if ($records = $DB->get_records_select('course_categories', $sql, $params, null, 'id, parent')) {
     455                      if (count($records) > 1) {
     456                          // Too many records with the same name!
     457                          $id = -1;
     458                          break;
     459                      }
     460                      $record = reset($records);
     461                      $id = $record->id;
     462                      $parent = $record->id;
     463                  } else {
     464                      // Not found.
     465                      $id = -1;
     466                      break;
     467                  }
     468              }
     469              $cache->set($cachekey, $id);
     470          }
     471  
     472          // We save -1 when the category has not been found to be able to know if the cache was set.
     473          if ($id == -1) {
     474              $id = false;
     475          }
     476          return $id;
     477      }
     478  
     479  }
    

    Search This Site: