Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 401 and 403] [Versions 402 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  declare(strict_types=1);
  18  
  19  namespace core_badges\reportbuilder\local\entities;
  20  
  21  use context_course;
  22  use context_helper;
  23  use context_system;
  24  use html_writer;
  25  use lang_string;
  26  use moodle_url;
  27  use stdClass;
  28  use core_reportbuilder\local\entities\base;
  29  use core_reportbuilder\local\filters\{select, text};
  30  use core_reportbuilder\local\report\{column, filter};
  31  
  32  defined('MOODLE_INTERNAL') or die;
  33  
  34  global $CFG;
  35  require_once("{$CFG->libdir}/badgeslib.php");
  36  
  37  /**
  38   * Badge entity
  39   *
  40   * @package     core_badges
  41   * @copyright   2022 Paul Holden <paulh@moodle.com>
  42   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  43   */
  44  class badge extends base {
  45  
  46      /**
  47       * Database tables that this entity uses and their default aliases
  48       *
  49       * @return array
  50       */
  51      protected function get_default_table_aliases(): array {
  52          return [
  53              'badge' => 'b',
  54              'context' => 'bctx',
  55              'tag_instance' => 'bti',
  56              'tag' => 'bt',
  57          ];
  58      }
  59  
  60      /**
  61       * The default title for this entity
  62       *
  63       * @return lang_string
  64       */
  65      protected function get_default_entity_title(): lang_string {
  66          return new lang_string('badgedetails', 'core_badges');
  67      }
  68  
  69      /**
  70       * Initialise the entity
  71       *
  72       * @return base
  73       */
  74      public function initialise(): base {
  75          $columns = $this->get_all_columns();
  76          foreach ($columns as $column) {
  77              $this->add_column($column);
  78          }
  79  
  80          // All the filters defined by the entity can also be used as conditions.
  81          $filters = $this->get_all_filters();
  82          foreach ($filters as $filter) {
  83              $this
  84                  ->add_filter($filter)
  85                  ->add_condition($filter);
  86          }
  87  
  88          return $this;
  89      }
  90  
  91      /**
  92       * Returns list of all available columns
  93       *
  94       * @return column[]
  95       */
  96      protected function get_all_columns(): array {
  97          global $DB;
  98  
  99          $badgealias = $this->get_table_alias('badge');
 100          $contextalias = $this->get_table_alias('context');
 101  
 102          // Name.
 103          $columns[] = (new column(
 104              'name',
 105              new lang_string('name'),
 106              $this->get_entity_name()
 107          ))
 108              ->add_joins($this->get_joins())
 109              ->set_type(column::TYPE_TEXT)
 110              ->add_field("{$badgealias}.name")
 111              ->set_is_sortable(true);
 112  
 113          // Name with link.
 114          $columns[] = (new column(
 115              'namewithlink',
 116              new lang_string('namewithlink', 'core_badges'),
 117              $this->get_entity_name()
 118          ))
 119              ->add_joins($this->get_joins())
 120              ->set_type(column::TYPE_TEXT)
 121              ->add_fields("{$badgealias}.name, {$badgealias}.id")
 122              ->set_is_sortable(true)
 123              ->add_callback(static function(?string $value, stdClass $row): string {
 124                  if (!$row->id) {
 125                      return '';
 126                  }
 127  
 128                  $url = new moodle_url('/badges/overview.php', ['id' => $row->id]);
 129                  return html_writer::link($url, $row->name);
 130              });
 131  
 132          // Description (note, this column contains plaintext so requires no post-processing).
 133          $descriptionfieldsql = "{$badgealias}.description";
 134          if ($DB->get_dbfamily() === 'oracle') {
 135              $descriptionfieldsql = $DB->sql_order_by_text($descriptionfieldsql, 1024);
 136          }
 137          $columns[] = (new column(
 138              'description',
 139              new lang_string('description', 'core_badges'),
 140              $this->get_entity_name()
 141          ))
 142              ->add_joins($this->get_joins())
 143              ->set_type(column::TYPE_LONGTEXT)
 144              ->add_field($descriptionfieldsql, 'description');
 145  
 146          // Criteria.
 147          $columns[] = (new column(
 148              'criteria',
 149              new lang_string('bcriteria', 'core_badges'),
 150              $this->get_entity_name()
 151          ))
 152              ->add_joins($this->get_joins())
 153              ->set_type(column::TYPE_TEXT)
 154              ->add_field("{$badgealias}.id")
 155              ->set_disabled_aggregation_all()
 156              ->add_callback(static function($badgeid): string {
 157                  global $PAGE;
 158                  if (!$badgeid) {
 159                      return '';
 160                  }
 161                  $badge = new \core_badges\badge($badgeid);
 162  
 163                  $renderer = $PAGE->get_renderer('core_badges');
 164                  return $renderer->print_badge_criteria($badge, 'short');
 165              });
 166  
 167          // Image.
 168          $columns[] = (new column(
 169              'image',
 170              new lang_string('badgeimage', 'core_badges'),
 171              $this->get_entity_name()
 172          ))
 173              ->add_joins($this->get_joins())
 174              ->add_join("LEFT JOIN {context} {$contextalias}
 175                      ON {$contextalias}.contextlevel = " . CONTEXT_COURSE . "
 176                     AND {$contextalias}.instanceid = {$badgealias}.courseid")
 177              ->set_type(column::TYPE_INTEGER)
 178              ->add_fields("{$badgealias}.id, {$badgealias}.type, {$badgealias}.courseid")
 179              ->add_field($DB->sql_cast_to_char("{$badgealias}.imagecaption"), 'imagecaption')
 180              ->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
 181              ->set_disabled_aggregation_all()
 182              ->add_callback(static function(?int $badgeid, stdClass $badge): string {
 183                  if (!$badgeid) {
 184                      return '';
 185                  }
 186                  if ($badge->type == BADGE_TYPE_SITE) {
 187                      $context = context_system::instance();
 188                  } else {
 189                      context_helper::preload_from_record($badge);
 190                      $context = context_course::instance($badge->courseid);
 191                  }
 192  
 193                  $badgeimage = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badgeid, '/', 'f2');
 194                  return html_writer::img($badgeimage, $badge->imagecaption);
 195              });
 196  
 197          // Language.
 198          $columns[] = (new column(
 199              'language',
 200              new lang_string('language'),
 201              $this->get_entity_name()
 202          ))
 203              ->add_joins($this->get_joins())
 204              ->set_type(column::TYPE_TEXT)
 205              ->add_field("{$badgealias}.language")
 206              ->set_is_sortable(true)
 207              ->add_callback(static function($language): string {
 208                  $languages = get_string_manager()->get_list_of_languages();
 209                  return $languages[$language] ?? $language ?? '';
 210              });
 211  
 212          // Version.
 213          $columns[] = (new column(
 214              'version',
 215              new lang_string('version', 'core_badges'),
 216              $this->get_entity_name()
 217          ))
 218              ->add_joins($this->get_joins())
 219              ->set_type(column::TYPE_TEXT)
 220              ->add_field("{$badgealias}.version")
 221              ->set_is_sortable(true);
 222  
 223          // Status.
 224          $columns[] = (new column(
 225              'status',
 226              new lang_string('status', 'core_badges'),
 227              $this->get_entity_name()
 228          ))
 229              ->add_joins($this->get_joins())
 230              ->set_type(column::TYPE_TEXT)
 231              ->add_field("{$badgealias}.status")
 232              ->set_is_sortable(true)
 233              ->add_callback(static function($status): string {
 234                  if ($status === null) {
 235                      return '';
 236                  }
 237  
 238                  return get_string("badgestatus_{$status}", 'core_badges');
 239              });
 240  
 241          // Expiry date/period.
 242          $columns[] = (new column(
 243              'expiry',
 244              new lang_string('expirydate', 'core_badges'),
 245              $this->get_entity_name()
 246          ))
 247              ->add_joins($this->get_joins())
 248              ->set_type(column::TYPE_TIMESTAMP)
 249              ->add_fields("{$badgealias}.expiredate, {$badgealias}.expireperiod, {$badgealias}.id")
 250              ->set_is_sortable(true, ["{$badgealias}.expiredate", "{$badgealias}.expireperiod"])
 251              ->set_disabled_aggregation_all()
 252              ->add_callback(static function(?int $expiredate, stdClass $badge): string {
 253                  if (!$badge->id) {
 254                      return '';
 255                  } else if ($expiredate) {
 256                      return userdate($expiredate);
 257                  } else if ($badge->expireperiod) {
 258                      return format_time($badge->expireperiod);
 259                  } else {
 260                      return get_string('never', 'core_badges');
 261                  }
 262              });
 263  
 264          // Image author details.
 265          foreach (['imageauthorname', 'imageauthoremail', 'imageauthorurl'] as $imageauthorfield) {
 266              $columns[] = (new column(
 267                  $imageauthorfield,
 268                  new lang_string($imageauthorfield, 'core_badges'),
 269                  $this->get_entity_name()
 270              ))
 271                  ->add_joins($this->get_joins())
 272                  ->set_type(column::TYPE_TEXT)
 273                  ->add_field("{$badgealias}.{$imageauthorfield}")
 274                  ->set_is_sortable(true);
 275          }
 276  
 277          return $columns;
 278      }
 279  
 280      /**
 281       * Return list of all available filters
 282       *
 283       * @return filter[]
 284       */
 285      protected function get_all_filters(): array {
 286          $badgealias = $this->get_table_alias('badge');
 287  
 288          // Name.
 289          $filters[] = (new filter(
 290              text::class,
 291              'name',
 292              new lang_string('name'),
 293              $this->get_entity_name(),
 294              "{$badgealias}.name"
 295          ))
 296              ->add_joins($this->get_joins());
 297  
 298          // Status.
 299          $filters[] = (new filter(
 300              select::class,
 301              'status',
 302              new lang_string('status', 'core_badges'),
 303              $this->get_entity_name(),
 304              "{$badgealias}.status"
 305          ))
 306              ->add_joins($this->get_joins())
 307              ->set_options([
 308                  BADGE_STATUS_INACTIVE => new lang_string('badgestatus_0', 'core_badges'),
 309                  BADGE_STATUS_ACTIVE => new lang_string('badgestatus_1', 'core_badges'),
 310                  BADGE_STATUS_INACTIVE_LOCKED => new lang_string('badgestatus_2', 'core_badges'),
 311                  BADGE_STATUS_ACTIVE_LOCKED => new lang_string('badgestatus_3', 'core_badges'),
 312                  BADGE_STATUS_ARCHIVED => new lang_string('badgestatus_4', 'core_badges'),
 313              ]);
 314  
 315          // Type.
 316          $filters[] = (new filter(
 317              select::class,
 318              'type',
 319              new lang_string('type', 'core_badges'),
 320              $this->get_entity_name(),
 321              "{$badgealias}.type"
 322          ))
 323              ->add_joins($this->get_joins())
 324              ->set_options([
 325                  BADGE_TYPE_SITE => new lang_string('site'),
 326                  BADGE_TYPE_COURSE => new lang_string('course'),
 327              ]);
 328  
 329          return $filters;
 330      }
 331  
 332      /**
 333       * Return joins necessary for retrieving tags
 334       *
 335       * @return string[]
 336       */
 337      public function get_tag_joins(): array {
 338          return $this->get_tag_joins_for_entity('core_badges', 'badge', $this->get_table_alias('badge') . '.id');
 339      }
 340  }