Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
/lib/ -> licenselib.php (source)

Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   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  /**
  20   * A namespace contains license specific functions
  21   *
  22   * @since      Moodle 2.0
  23   * @package    core
  24   * @subpackage lib
  25   * @copyright  2010 Dongsheng Cai <dongsheng@moodle.com>
  26   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  class license_manager {
  32  
  33      /**
  34       * License is a core license and can not be updated or deleted.
  35       */
  36      const CORE_LICENSE = 0;
  37  
  38      /**
  39       * License is a custom license and can be updated and/or deleted.
  40       */
  41      const CUSTOM_LICENSE = 1;
  42  
  43      /**
  44       * Integer representation of boolean for a license that is enabled.
  45       */
  46      const LICENSE_ENABLED = 1;
  47  
  48      /**
  49       * Integer representation of boolean for a license that is disabled.
  50       */
  51      const LICENSE_DISABLED = 0;
  52  
  53      /**
  54       * Integer for moving a license up order.
  55       */
  56      const LICENSE_MOVE_UP = -1;
  57  
  58      /**
  59       * Integer for moving a license down order.
  60       */
  61      const LICENSE_MOVE_DOWN = 1;
  62  
  63      /**
  64       * Save a license record.
  65       *
  66       * @param object $license {
  67       *            shortname => string a shortname of license, will be refered by files table[required]
  68       *            fullname  => string the fullname of the license [required]
  69       *            source => string the homepage of the license type[required]
  70       *            enabled => int is it enabled?
  71       *            version  => int a version number used by moodle [required]
  72       * }
  73       */
  74      static public function save($license) {
  75  
  76          $existinglicense = self::get_license_by_shortname($license->shortname);
  77  
  78          if (!empty($existinglicense)) {
  79              $id = $existinglicense->id;
  80              if ($existinglicense->custom == self::CORE_LICENSE) {
  81                  // Can only update the enabled status and sortorder for core licenses.
  82                  $existinglicense->enabled = $license->enabled;
  83                  $existinglicense->sortorder = $license->sortorder;
  84                  $license = $existinglicense;
  85              }
  86              $license->id = $id;
  87              self::update($license);
  88          } else {
  89              self::create($license);
  90          }
  91  
  92          return true;
  93      }
  94  
  95      /**
  96       * Adding a new license type
  97       *
  98       * @deprecated Since Moodle 3.9, MDL-45184.
  99       * @todo MDL-67344 This will be deleted in Moodle 4.1.
 100       * @see license_manager::save()
 101       *
 102       * @param object $license the license record to add.
 103       *
 104       * @return bool true on success.
 105       */
 106      public function add($license) : bool {
 107          debugging('add() is deprecated. Please use license_manager::save() instead.', DEBUG_DEVELOPER);
 108  
 109          return self::save($license);
 110      }
 111  
 112      /**
 113       * Create a license record.
 114       *
 115       * @param object $license the license to create record for.
 116       */
 117      static protected function create($license) {
 118          global $DB;
 119  
 120          $licensecount = count(self::get_licenses());
 121          $license->sortorder = $licensecount + 1;
 122          // Enable all created license by default.
 123          $license->enabled = self::LICENSE_ENABLED;
 124          // API can only create custom licenses, core licenses
 125          // are directly created at install or upgrade.
 126          $license->custom = self::CUSTOM_LICENSE;
 127  
 128          $DB->insert_record('license', $license);
 129          self::reset_license_cache();
 130          // Update the config setting of active licenses.
 131          self::set_active_licenses();
 132      }
 133  
 134      /**
 135       * Read licens record(s) from database.
 136       *
 137       * @param array $params license parameters to return licenses for.
 138       *
 139       * @return array $filteredlicenses object[] of licenses.
 140       */
 141      static public function read(array $params = []) {
 142          $licenses = self::get_licenses();
 143  
 144          $filteredlicenses = [];
 145  
 146          foreach ($licenses as $shortname => $license) {
 147              $filtermatch = true;
 148              foreach ($params as $key => $value) {
 149                  if ($license->$key != $value) {
 150                      $filtermatch = false;
 151                  }
 152              }
 153              if ($filtermatch) {
 154                  $filteredlicenses[$shortname] = $license;
 155              }
 156          }
 157          return $filteredlicenses;
 158  
 159      }
 160  
 161      /**
 162       * Update a license record.
 163       *
 164       * @param object $license the license to update record for.
 165       *
 166       * @throws \moodle_exception if attempting to update a core license.
 167       */
 168      static protected function update($license) {
 169          global $DB;
 170  
 171          $DB->update_record('license', $license);
 172          self::reset_license_cache();
 173      }
 174  
 175      /**
 176       * Delete a custom license.
 177       *
 178       * @param string $licenseshortname the shortname of license.
 179       *
 180       * @throws \moodle_exception when attempting to delete a license you are not allowed to.
 181       */
 182      static public function delete($licenseshortname) {
 183          global $DB;
 184  
 185          $licensetodelete = self::get_license_by_shortname($licenseshortname);
 186  
 187          if (!empty($licensetodelete)) {
 188              if ($licensetodelete->custom == self::CUSTOM_LICENSE) {
 189                  // Check that the license is not in use by any non-draft files, if so it cannot be deleted.
 190                  $countfilesselect = 'license = :license AND NOT (component = \'user\' AND filearea = \'draft\')';
 191                  $countfilesusinglicense = $DB->count_records_select('files', $countfilesselect, ['license' => $licenseshortname]);
 192                  if ($countfilesusinglicense > 0) {
 193                      throw new moodle_exception('cannotdeletelicenseinuse', 'license');
 194                  }
 195                  $deletedsortorder = $licensetodelete->sortorder;
 196                  $DB->delete_records('license', ['id' => $licensetodelete->id]);
 197  
 198                  // We've deleted a license, so update our list of licenses so we don't save the deleted license again.
 199                  self::reset_license_cache();
 200                  $licenses = self::get_licenses();
 201  
 202                  foreach ($licenses as $license) {
 203                      if ($license->sortorder > $deletedsortorder) {
 204                          $license->sortorder = $license->sortorder - 1;
 205                          self::save($license);
 206                      }
 207                  }
 208  
 209                  // Update the config setting of active licenses as well.
 210                  self::set_active_licenses();
 211  
 212              } else {
 213                  throw new moodle_exception('cannotdeletecore', 'license');
 214              }
 215          } else {
 216              throw new moodle_exception('licensenotfoundshortname', 'license', $licenseshortname);
 217          }
 218      }
 219  
 220      /**
 221       * Get license records.
 222       *
 223       * @return array|false object[] of license records of false if none.
 224       */
 225      static public function get_licenses() {
 226          global $DB;
 227  
 228          $cache = \cache::make('core', 'license');
 229          $licenses = $cache->get('licenses');
 230  
 231          if ($licenses === false) {
 232              $licenses = [];
 233              $records = $DB->get_records_select('license', null, null, 'sortorder ASC');
 234              foreach ($records as $license) {
 235                  $licenses[$license->shortname] = $license;
 236              }
 237              $cache->set('licenses', $licenses);
 238          }
 239  
 240          foreach ($licenses as $license) {
 241              // Localise the license names.
 242              if ($license->custom == self::CORE_LICENSE) {
 243                  $license->fullname = get_string($license->shortname, 'core_license');
 244              } else {
 245                  $license->fullname = format_string($license->fullname);
 246              }
 247          }
 248  
 249          return $licenses;
 250      }
 251  
 252      /**
 253       * Change the sort order of a license (and it's sibling license as a result).
 254       *
 255       * @param int $direction value to change sortorder of license by.
 256       * @param string $licenseshortname the shortname of license to changes sortorder for.
 257       *
 258       * @throws \moodle_exception if attempting to use invalid direction value.
 259       */
 260      static public function change_license_sortorder(int $direction, string $licenseshortname) : void {
 261  
 262          if ($direction != self::LICENSE_MOVE_UP && $direction != self::LICENSE_MOVE_DOWN) {
 263              throw new coding_exception(
 264                  'Must use a valid licence API move direction constant (LICENSE_MOVE_UP or LICENSE_MOVE_DOWN)');
 265          }
 266  
 267          $licenses = self::get_licenses();
 268          $licensetoupdate = $licenses[$licenseshortname];
 269  
 270          $currentsortorder = $licensetoupdate->sortorder;
 271          $targetsortorder = $currentsortorder + $direction;
 272  
 273          if ($targetsortorder > 0 && $targetsortorder <= count($licenses) ) {
 274              foreach ($licenses as $license) {
 275                  if ($license->sortorder == $targetsortorder) {
 276                      $license->sortorder = $license->sortorder - $direction;
 277                      self::update($license);
 278                  }
 279              }
 280              $licensetoupdate->sortorder = $targetsortorder;
 281              self::update($licensetoupdate);
 282          }
 283      }
 284  
 285      /**
 286       * Get license record by shortname
 287       *
 288       * @param string $name the shortname of license
 289       * @return object|null the license or null if no license found.
 290       */
 291      static public function get_license_by_shortname(string $name) {
 292          $licenses = self::read(['shortname' => $name]);
 293  
 294          if (!empty($licenses)) {
 295              $license = reset($licenses);
 296          } else {
 297              $license = null;
 298          }
 299  
 300          return $license;
 301      }
 302  
 303      /**
 304       * Enable a license
 305       * @param string $license the shortname of license
 306       * @return boolean
 307       */
 308      static public function enable($license) {
 309          if ($license = self::get_license_by_shortname($license)) {
 310              $license->enabled = self::LICENSE_ENABLED;
 311              self::update($license);
 312          }
 313          self::set_active_licenses();
 314  
 315          return true;
 316      }
 317  
 318      /**
 319       * Disable a license
 320       * @param string $license the shortname of license
 321       * @return boolean
 322       */
 323      static public function disable($license) {
 324          global $CFG;
 325          // Site default license cannot be disabled!
 326          if ($license == $CFG->sitedefaultlicense) {
 327              print_error('error');
 328          }
 329          if ($license = self::get_license_by_shortname($license)) {
 330              $license->enabled = self::LICENSE_DISABLED;
 331              self::update($license);
 332          }
 333          self::set_active_licenses();
 334  
 335          return true;
 336      }
 337  
 338      /**
 339       * Store active licenses in global config.
 340       */
 341      static protected function set_active_licenses() {
 342          $licenses = self::read(['enabled' => self::LICENSE_ENABLED]);
 343          $result = array();
 344          foreach ($licenses as $l) {
 345              $result[] = $l->shortname;
 346          }
 347          set_config('licenses', implode(',', $result));
 348      }
 349  
 350      /**
 351       * Get the globally configured active licenses.
 352       *
 353       * @return array of license objects.
 354       * @throws \coding_exception
 355       */
 356      static public function get_active_licenses() {
 357          global $CFG;
 358  
 359          $result = [];
 360  
 361          if (!empty($CFG->licenses)) {
 362              $activelicenses = explode(',', $CFG->licenses);
 363              $licenses = self::get_licenses();
 364              foreach ($licenses as $license) {
 365                  if (in_array($license->shortname, $activelicenses)) {
 366                      $result[$license->shortname] = $license;
 367                  }
 368              }
 369          }
 370  
 371          return $result;
 372      }
 373  
 374      /**
 375       * Get the globally configured active licenses as an array.
 376       *
 377       * @return array $licenses an associative array of licenses shaped as ['shortname' => 'fullname']
 378       */
 379      static public function get_active_licenses_as_array() {
 380          $activelicenses = self::get_active_licenses();
 381  
 382          $licenses = [];
 383          foreach ($activelicenses as $license) {
 384              $licenses[$license->shortname] = $license->fullname;
 385          }
 386  
 387          return $licenses;
 388      }
 389  
 390      /**
 391       * Install moodle built-in licenses.
 392       */
 393      static public function install_licenses() {
 394          global $CFG;
 395  
 396          require_once($CFG->libdir . '/db/upgradelib.php');
 397  
 398          upgrade_core_licenses();
 399      }
 400  
 401      /**
 402       * Reset the license cache so it rebuilds next time licenses are fetched.
 403       */
 404      static public function reset_license_cache() {
 405          $cache = \cache::make('core', 'license');
 406          $cache->delete('licenses');
 407      }
 408  }