Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
/lib/ -> licenselib.php (source)

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

   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       * @deprecated Since Moodle 3.9, MDL-45184.
  97       */
  98      public function add() {
  99          throw new coding_exception('license_manager::add() is deprecated. Please use license_manager::save() instead.');
 100      }
 101  
 102      /**
 103       * Create a license record.
 104       *
 105       * @param object $license the license to create record for.
 106       */
 107      static protected function create($license) {
 108          global $DB;
 109  
 110          $licensecount = count(self::get_licenses());
 111          $license->sortorder = $licensecount + 1;
 112          // Enable all created license by default.
 113          $license->enabled = self::LICENSE_ENABLED;
 114          // API can only create custom licenses, core licenses
 115          // are directly created at install or upgrade.
 116          $license->custom = self::CUSTOM_LICENSE;
 117  
 118          $DB->insert_record('license', $license);
 119          self::reset_license_cache();
 120          // Update the config setting of active licenses.
 121          self::set_active_licenses();
 122      }
 123  
 124      /**
 125       * Read licens record(s) from database.
 126       *
 127       * @param array $params license parameters to return licenses for.
 128       *
 129       * @return array $filteredlicenses object[] of licenses.
 130       */
 131      static public function read(array $params = []) {
 132          $licenses = self::get_licenses();
 133  
 134          $filteredlicenses = [];
 135  
 136          foreach ($licenses as $shortname => $license) {
 137              $filtermatch = true;
 138              foreach ($params as $key => $value) {
 139                  if ($license->$key != $value) {
 140                      $filtermatch = false;
 141                  }
 142              }
 143              if ($filtermatch) {
 144                  $filteredlicenses[$shortname] = $license;
 145              }
 146          }
 147          return $filteredlicenses;
 148  
 149      }
 150  
 151      /**
 152       * Update a license record.
 153       *
 154       * @param object $license the license to update record for.
 155       *
 156       * @throws \moodle_exception if attempting to update a core license.
 157       */
 158      static protected function update($license) {
 159          global $DB;
 160  
 161          $DB->update_record('license', $license);
 162          self::reset_license_cache();
 163      }
 164  
 165      /**
 166       * Delete a custom license.
 167       *
 168       * @param string $licenseshortname the shortname of license.
 169       *
 170       * @throws \moodle_exception when attempting to delete a license you are not allowed to.
 171       */
 172      static public function delete($licenseshortname) {
 173          global $DB;
 174  
 175          $licensetodelete = self::get_license_by_shortname($licenseshortname);
 176  
 177          if (!empty($licensetodelete)) {
 178              if ($licensetodelete->custom == self::CUSTOM_LICENSE) {
 179                  // Check that the license is not in use by any non-draft files, if so it cannot be deleted.
 180                  $countfilesselect = 'license = :license AND NOT (component = \'user\' AND filearea = \'draft\')';
 181                  $countfilesusinglicense = $DB->count_records_select('files', $countfilesselect, ['license' => $licenseshortname]);
 182                  if ($countfilesusinglicense > 0) {
 183                      throw new moodle_exception('cannotdeletelicenseinuse', 'license');
 184                  }
 185                  $deletedsortorder = $licensetodelete->sortorder;
 186                  $DB->delete_records('license', ['id' => $licensetodelete->id]);
 187  
 188                  // We've deleted a license, so update our list of licenses so we don't save the deleted license again.
 189                  self::reset_license_cache();
 190                  $licenses = self::get_licenses();
 191  
 192                  foreach ($licenses as $license) {
 193                      if ($license->sortorder > $deletedsortorder) {
 194                          $license->sortorder = $license->sortorder - 1;
 195                          self::save($license);
 196                      }
 197                  }
 198  
 199                  // Update the config setting of active licenses as well.
 200                  self::set_active_licenses();
 201  
 202              } else {
 203                  throw new moodle_exception('cannotdeletecore', 'license');
 204              }
 205          } else {
 206              throw new moodle_exception('licensenotfoundshortname', 'license', $licenseshortname);
 207          }
 208      }
 209  
 210      /**
 211       * Get license records.
 212       *
 213       * @return array|false object[] of license records of false if none.
 214       */
 215      static public function get_licenses() {
 216          global $DB;
 217  
 218          $cache = \cache::make('core', 'license');
 219          $licenses = $cache->get('licenses');
 220  
 221          if ($licenses === false) {
 222              $licenses = [];
 223              $records = $DB->get_records_select('license', null, null, 'sortorder ASC');
 224              foreach ($records as $license) {
 225                  $licenses[$license->shortname] = $license;
 226              }
 227              $cache->set('licenses', $licenses);
 228          }
 229  
 230          foreach ($licenses as $license) {
 231              // Localise the license names.
 232              if ($license->custom == self::CORE_LICENSE) {
 233                  $license->fullname = get_string($license->shortname, 'core_license');
 234              } else {
 235                  $license->fullname = format_string($license->fullname);
 236              }
 237          }
 238  
 239          return $licenses;
 240      }
 241  
 242      /**
 243       * Change the sort order of a license (and it's sibling license as a result).
 244       *
 245       * @param int $direction value to change sortorder of license by.
 246       * @param string $licenseshortname the shortname of license to changes sortorder for.
 247       *
 248       * @throws \moodle_exception if attempting to use invalid direction value.
 249       */
 250      static public function change_license_sortorder(int $direction, string $licenseshortname) : void {
 251  
 252          if ($direction != self::LICENSE_MOVE_UP && $direction != self::LICENSE_MOVE_DOWN) {
 253              throw new coding_exception(
 254                  'Must use a valid licence API move direction constant (LICENSE_MOVE_UP or LICENSE_MOVE_DOWN)');
 255          }
 256  
 257          $licenses = self::get_licenses();
 258          $licensetoupdate = $licenses[$licenseshortname];
 259  
 260          $currentsortorder = $licensetoupdate->sortorder;
 261          $targetsortorder = $currentsortorder + $direction;
 262  
 263          if ($targetsortorder > 0 && $targetsortorder <= count($licenses) ) {
 264              foreach ($licenses as $license) {
 265                  if ($license->sortorder == $targetsortorder) {
 266                      $license->sortorder = $license->sortorder - $direction;
 267                      self::update($license);
 268                  }
 269              }
 270              $licensetoupdate->sortorder = $targetsortorder;
 271              self::update($licensetoupdate);
 272          }
 273      }
 274  
 275      /**
 276       * Get license record by shortname
 277       *
 278       * @param string $name the shortname of license
 279       * @return object|null the license or null if no license found.
 280       */
 281      static public function get_license_by_shortname(string $name) {
 282          $licenses = self::read(['shortname' => $name]);
 283  
 284          if (!empty($licenses)) {
 285              $license = reset($licenses);
 286          } else {
 287              $license = null;
 288          }
 289  
 290          return $license;
 291      }
 292  
 293      /**
 294       * Enable a license
 295       * @param string $license the shortname of license
 296       * @return boolean
 297       */
 298      static public function enable($license) {
 299          if ($license = self::get_license_by_shortname($license)) {
 300              $license->enabled = self::LICENSE_ENABLED;
 301              self::update($license);
 302          }
 303          self::set_active_licenses();
 304  
 305          return true;
 306      }
 307  
 308      /**
 309       * Disable a license
 310       * @param string $license the shortname of license
 311       * @return boolean
 312       */
 313      static public function disable($license) {
 314          global $CFG;
 315          // Site default license cannot be disabled!
 316          if ($license == $CFG->sitedefaultlicense) {
 317              throw new \moodle_exception('error');
 318          }
 319          if ($license = self::get_license_by_shortname($license)) {
 320              $license->enabled = self::LICENSE_DISABLED;
 321              self::update($license);
 322          }
 323          self::set_active_licenses();
 324  
 325          return true;
 326      }
 327  
 328      /**
 329       * Store active licenses in global config.
 330       */
 331      static protected function set_active_licenses() {
 332          $licenses = self::read(['enabled' => self::LICENSE_ENABLED]);
 333          $result = array();
 334          foreach ($licenses as $l) {
 335              $result[] = $l->shortname;
 336          }
 337          set_config('licenses', implode(',', $result));
 338      }
 339  
 340      /**
 341       * Get the globally configured active licenses.
 342       *
 343       * @return array of license objects.
 344       * @throws \coding_exception
 345       */
 346      static public function get_active_licenses() {
 347          global $CFG;
 348  
 349          $result = [];
 350  
 351          if (!empty($CFG->licenses)) {
 352              $activelicenses = explode(',', $CFG->licenses);
 353              $licenses = self::get_licenses();
 354              foreach ($licenses as $license) {
 355                  if (in_array($license->shortname, $activelicenses)) {
 356                      $result[$license->shortname] = $license;
 357                  }
 358              }
 359          }
 360  
 361          return $result;
 362      }
 363  
 364      /**
 365       * Get the globally configured active licenses as an array.
 366       *
 367       * @return array $licenses an associative array of licenses shaped as ['shortname' => 'fullname']
 368       */
 369      static public function get_active_licenses_as_array() {
 370          $activelicenses = self::get_active_licenses();
 371  
 372          $licenses = [];
 373          foreach ($activelicenses as $license) {
 374              $licenses[$license->shortname] = $license->fullname;
 375          }
 376  
 377          return $licenses;
 378      }
 379  
 380      /**
 381       * Install moodle built-in licenses.
 382       */
 383      static public function install_licenses() {
 384          global $CFG;
 385  
 386          require_once($CFG->libdir . '/db/upgradelib.php');
 387  
 388          upgrade_core_licenses();
 389      }
 390  
 391      /**
 392       * Reset the license cache so it rebuilds next time licenses are fetched.
 393       */
 394      static public function reset_license_cache() {
 395          $cache = \cache::make('core', 'license');
 396          $cache->delete('licenses');
 397      }
 398  }