Search moodle.org's
Developer Documentation

See Release Notes

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

Differences Between: [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          ];
  56      }
  57  
  58      /**
  59       * The default title for this entity
  60       *
  61       * @return lang_string
  62       */
  63      protected function get_default_entity_title(): lang_string {
  64          return new lang_string('badgedetails', 'core_badges');
  65      }
  66  
  67      /**
  68       * Initialise the entity
  69       *
  70       * @return base
  71       */
  72      public function initialise(): base {
  73          $columns = $this->get_all_columns();
  74          foreach ($columns as $column) {
  75              $this->add_column($column);
  76          }
  77  
  78          // All the filters defined by the entity can also be used as conditions.
  79          $filters = $this->get_all_filters();
  80          foreach ($filters as $filter) {
  81              $this
  82                  ->add_filter($filter)
  83                  ->add_condition($filter);
  84          }
  85  
  86          return $this;
  87      }
  88  
  89      /**
  90       * Returns list of all available columns
  91       *
  92       * @return column[]
  93       */
  94      protected function get_all_columns(): array {
  95          global $DB;
  96  
  97          $badgealias = $this->get_table_alias('badge');
  98          $contextalias = $this->get_table_alias('context');
  99  
 100          // Name.
 101          $columns[] = (new column(
 102              'name',
 103              new lang_string('name'),
 104              $this->get_entity_name()
 105          ))
 106              ->add_joins($this->get_joins())
 107              ->set_type(column::TYPE_TEXT)
 108              ->add_field("{$badgealias}.name")
 109              ->set_is_sortable(true);
 110  
 111          // Description (note, this column contains plaintext so requires no post-processing).
 112          $descriptionfieldsql = "{$badgealias}.description";
 113          if ($DB->get_dbfamily() === 'oracle') {
 114              $descriptionfieldsql = $DB->sql_order_by_text($descriptionfieldsql, 1024);
 115          }
 116          $columns[] = (new column(
 117              'description',
 118              new lang_string('description', 'core_badges'),
 119              $this->get_entity_name()
 120          ))
 121              ->add_joins($this->get_joins())
 122              ->set_type(column::TYPE_LONGTEXT)
 123              ->add_field($descriptionfieldsql, 'description');
 124  
 125          // Criteria.
 126          $columns[] = (new column(
 127              'criteria',
 128              new lang_string('bcriteria', 'core_badges'),
 129              $this->get_entity_name()
 130          ))
 131              ->add_joins($this->get_joins())
 132              ->set_type(column::TYPE_TEXT)
 133              ->add_field("{$badgealias}.id")
 134              ->set_disabled_aggregation_all()
 135              ->add_callback(static function($badgeid): string {
 136                  global $PAGE;
 137                  if (!$badgeid) {
 138                      return '';
 139                  }
 140                  $badge = new \core_badges\badge($badgeid);
 141  
 142                  $renderer = $PAGE->get_renderer('core_badges');
 143                  return $renderer->print_badge_criteria($badge, 'short');
 144              });
 145  
 146          // Image.
 147          $columns[] = (new column(
 148              'image',
 149              new lang_string('badgeimage', 'core_badges'),
 150              $this->get_entity_name()
 151          ))
 152              ->add_joins($this->get_joins())
 153              ->add_join("LEFT JOIN {context} {$contextalias}
 154                      ON {$contextalias}.contextlevel = " . CONTEXT_COURSE . "
 155                     AND {$contextalias}.instanceid = {$badgealias}.courseid")
 156              ->set_type(column::TYPE_INTEGER)
 157              ->add_fields("{$badgealias}.id, {$badgealias}.type, {$badgealias}.courseid")
 158              ->add_field($DB->sql_cast_to_char("{$badgealias}.imagecaption"), 'imagecaption')
 159              ->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
 160              ->set_disabled_aggregation_all()
 161              ->add_callback(static function(?int $badgeid, stdClass $badge): string {
 162                  if (!$badgeid) {
 163                      return '';
 164                  }
 165                  if ($badge->type == BADGE_TYPE_SITE) {
 166                      $context = context_system::instance();
 167                  } else {
 168                      context_helper::preload_from_record($badge);
 169                      $context = context_course::instance($badge->courseid);
 170                  }
 171  
 172                  $badgeimage = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badgeid, '/', 'f2');
 173                  return html_writer::img($badgeimage, $badge->imagecaption);
 174              });
 175  
 176          // Language.
 177          $columns[] = (new column(
 178              'language',
 179              new lang_string('language'),
 180              $this->get_entity_name()
 181          ))
 182              ->add_joins($this->get_joins())
 183              ->set_type(column::TYPE_TEXT)
 184              ->add_field("{$badgealias}.language")
 185              ->set_is_sortable(true)
 186              ->add_callback(static function($language): string {
 187                  $languages = get_string_manager()->get_list_of_languages();
 188                  return $languages[$language] ?? $language ?? '';
 189              });
 190  
 191          // Version.
 192          $columns[] = (new column(
 193              'version',
 194              new lang_string('version', 'core_badges'),
 195              $this->get_entity_name()
 196          ))
 197              ->add_joins($this->get_joins())
 198              ->set_type(column::TYPE_TEXT)
 199              ->add_field("{$badgealias}.version")
 200              ->set_is_sortable(true);
 201  
 202          // Status.
 203          $columns[] = (new column(
 204              'status',
 205              new lang_string('status', 'core_badges'),
 206              $this->get_entity_name()
 207          ))
 208              ->add_joins($this->get_joins())
 209              ->set_type(column::TYPE_TEXT)
 210              ->add_field("{$badgealias}.status")
 211              ->set_is_sortable(true)
 212              ->add_callback(static function($status): string {
 213                  return $status ? get_string("badgestatus_{$status}", 'core_badges') : '';
 214              });
 215  
 216          // Expiry date/period.
 217          $columns[] = (new column(
 218              'expiry',
 219              new lang_string('expirydate', 'core_badges'),
 220              $this->get_entity_name()
 221          ))
 222              ->add_joins($this->get_joins())
 223              ->set_type(column::TYPE_TIMESTAMP)
 224              ->add_fields("{$badgealias}.expiredate, {$badgealias}.expireperiod, {$badgealias}.id")
 225              ->set_is_sortable(true, ["{$badgealias}.expiredate", "{$badgealias}.expireperiod"])
 226              ->set_disabled_aggregation_all()
 227              ->add_callback(static function(?int $expiredate, stdClass $badge): string {
 228                  if (!$badge->id) {
 229                      return '';
 230                  } else if ($expiredate) {
 231                      return userdate($expiredate);
 232                  } else if ($badge->expireperiod) {
 233                      return format_time($badge->expireperiod);
 234                  } else {
 235                      return get_string('never', 'core_badges');
 236                  }
 237              });
 238  
 239          // Image author details.
 240          foreach (['imageauthorname', 'imageauthoremail', 'imageauthorurl'] as $imageauthorfield) {
 241              $columns[] = (new column(
 242                  $imageauthorfield,
 243                  new lang_string($imageauthorfield, 'core_badges'),
 244                  $this->get_entity_name()
 245              ))
 246                  ->add_joins($this->get_joins())
 247                  ->set_type(column::TYPE_TEXT)
 248                  ->add_field("{$badgealias}.{$imageauthorfield}")
 249                  ->set_is_sortable(true);
 250          }
 251  
 252          return $columns;
 253      }
 254  
 255      /**
 256       * Return list of all available filters
 257       *
 258       * @return filter[]
 259       */
 260      protected function get_all_filters(): array {
 261          $badgealias = $this->get_table_alias('badge');
 262  
 263          // Name.
 264          $filters[] = (new filter(
 265              text::class,
 266              'name',
 267              new lang_string('name'),
 268              $this->get_entity_name(),
 269              "{$badgealias}.name"
 270          ))
 271              ->add_joins($this->get_joins());
 272  
 273          // Status.
 274          $filters[] = (new filter(
 275              select::class,
 276              'status',
 277              new lang_string('status', 'core_badges'),
 278              $this->get_entity_name(),
 279              "{$badgealias}.status"
 280          ))
 281              ->add_joins($this->get_joins())
 282              ->set_options([
 283                  BADGE_STATUS_INACTIVE => new lang_string('badgestatus_0', 'core_badges'),
 284                  BADGE_STATUS_ACTIVE => new lang_string('badgestatus_1', 'core_badges'),
 285                  BADGE_STATUS_INACTIVE_LOCKED => new lang_string('badgestatus_2', 'core_badges'),
 286                  BADGE_STATUS_ACTIVE_LOCKED => new lang_string('badgestatus_3', 'core_badges'),
 287                  BADGE_STATUS_ARCHIVED => new lang_string('badgestatus_4', 'core_badges'),
 288              ]);
 289  
 290          // Type.
 291          $filters[] = (new filter(
 292              select::class,
 293              'type',
 294              new lang_string('type', 'core_badges'),
 295              $this->get_entity_name(),
 296              "{$badgealias}.type"
 297          ))
 298              ->add_joins($this->get_joins())
 299              ->set_options([
 300                  BADGE_TYPE_SITE => new lang_string('site'),
 301                  BADGE_TYPE_COURSE => new lang_string('course'),
 302              ]);
 303  
 304          return $filters;
 305      }
 306  }