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.

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

   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   * Forum summary report filters renderable.
  19   *
  20   * @package    forumreport_summary
  21   * @copyright  2019 Michael Hawkins <michaelh@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace forumreport_summary\output;
  26  
  27  use context_course;
  28  use moodle_url;
  29  use renderable;
  30  use renderer_base;
  31  use stdClass;
  32  use templatable;
  33  use forumreport_summary;
  34  
  35  /**
  36   * Forum summary report filters renderable.
  37   *
  38   * @copyright  2019 Michael Hawkins <michaelh@moodle.com>
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class filters implements renderable, templatable {
  42  
  43      /**
  44       * Course modules the report relates to.
  45       * Array of stdClass objects
  46       *
  47       * @var array $cms
  48       */
  49      protected $cms;
  50  
  51      /**
  52       * Course ID where the report is being generated.
  53       *
  54       * @var int $courseid
  55       */
  56      protected $courseid;
  57  
  58      /**
  59       * Moodle URL used as the form action on the generate button.
  60       *
  61       * @var moodle_url $actionurl
  62       */
  63      protected $actionurl;
  64  
  65      /**
  66       * Details of groups available for filtering.
  67       * Stored in the format groupid => groupname.
  68       *
  69       * @var array $groupsavailable
  70       */
  71      protected $groupsavailable = [];
  72  
  73      /**
  74       * IDs of groups selected for filtering.
  75       *
  76       * @var array $groupsselected
  77       */
  78      protected $groupsselected = [];
  79  
  80      /**
  81       * IDs of discussions required for export links.
  82       * If a subset of groups available are selected, this will include the discussion IDs
  83       * within that group in the forum.
  84       * If all groups are selected, or no groups mode is enabled, this will be empty as
  85       * no discussion filtering is required in the export.
  86       *
  87       * @var array $discussionids
  88       */
  89      protected $discussionids = [];
  90  
  91      /**
  92       * HTML for dates filter.
  93       *
  94       * @var array $datesdata
  95       */
  96      protected $datesdata = [];
  97  
  98      /**
  99       * Text to display on the dates filter button.
 100       *
 101       * @var string $datesbuttontext
 102       */
 103      protected $datesbuttontext;
 104  
 105      /**
 106       * Builds renderable filter data.
 107       *
 108       * @param stdClass $course The course object.
 109       * @param array $cms Array of course module objects.
 110       * @param moodle_url $actionurl The form action URL.
 111       * @param array $filterdata (optional) Associative array of data that has been set on available filters, if any,
 112       *                                     in the format filtertype => [values]
 113       */
 114      public function __construct(stdClass $course, array $cms, moodle_url $actionurl, array $filterdata = []) {
 115          $this->cms = $cms;
 116          $this->courseid = $course->id;
 117          $this->actionurl = $actionurl;
 118  
 119          // Prepare groups filter data.
 120          $groupsdata = $filterdata['groups'] ?? [];
 121          $this->prepare_groups_data($groupsdata);
 122  
 123          // Prepare dates filter data.
 124          $datefromdata = $filterdata['datefrom'] ?? [];
 125          $datetodata = $filterdata['dateto'] ?? [];
 126          $this->prepare_dates_data($datefromdata, $datetodata);
 127      }
 128  
 129      /**
 130       * Prepares groups data and sets relevant property values.
 131       *
 132       * @param array $groupsdata Groups selected for filtering.
 133       * @return void.
 134       */
 135      protected function prepare_groups_data(array $groupsdata): void {
 136          global $DB, $USER;
 137  
 138          $groupsavailable = [];
 139          $allowedgroupsobj = [];
 140  
 141          $usergroups = groups_get_all_groups($this->courseid, $USER->id);
 142          $coursegroups = groups_get_all_groups($this->courseid);
 143          $forumids = [];
 144          $allgroups = false;
 145          $hasgroups = false;
 146  
 147          // Check if any forum gives the user access to all groups and no groups.
 148          foreach ($this->cms as $cm) {
 149              $forumids[] = $cm->instance;
 150  
 151              // Only need to check for all groups access if not confirmed by a previous check.
 152              if (!$allgroups) {
 153                  $groupmode = groups_get_activity_groupmode($cm);
 154  
 155                  // If no groups mode enabled on the forum, nothing to prepare.
 156                  if (!in_array($groupmode, [VISIBLEGROUPS, SEPARATEGROUPS])) {
 157                      continue;
 158                  }
 159  
 160                  $hasgroups = true;
 161  
 162                  // Fetch for the current cm's forum.
 163                  $context = \context_module::instance($cm->id);
 164                  $aag = has_capability('moodle/site:accessallgroups', $context);
 165  
 166                  if ($groupmode == VISIBLEGROUPS || $aag) {
 167                      $allgroups = true;
 168                  }
 169              }
 170          }
 171  
 172          // If no groups mode enabled, nothing to prepare.
 173          if (!$hasgroups) {
 174              return;
 175          }
 176  
 177          // Any groups, and no groups.
 178          if ($allgroups) {
 179              $nogroups = new stdClass();
 180              $nogroups->id = -1;
 181              $nogroups->name = get_string('groupsnone');
 182  
 183              $allowedgroupsobj = $coursegroups + [$nogroups];
 184          } else {
 185              $allowedgroupsobj = $usergroups;
 186          }
 187  
 188          $contextcourse = context_course::instance($this->courseid);
 189          foreach ($allowedgroupsobj as $group) {
 190              $groupsavailable[$group->id] = format_string($group->name, true, ['context' => $contextcourse]);
 191          }
 192  
 193          // Set valid groups selected.
 194          $groupsselected = array_intersect($groupsdata, array_keys($groupsavailable));
 195  
 196          // Overwrite groups properties.
 197          $this->groupsavailable = $groupsavailable;
 198          $this->groupsselected = $groupsselected;
 199  
 200          $groupsselectedcount = count($groupsselected);
 201          if ($groupsselectedcount > 0 && $groupsselectedcount < count($groupsavailable)) {
 202              list($forumidin, $forumidparams) = $DB->get_in_or_equal($forumids, SQL_PARAMS_NAMED);
 203              list($groupidin, $groupidparams) = $DB->get_in_or_equal($groupsselected, SQL_PARAMS_NAMED);
 204  
 205              $discussionswhere = "course = :courseid AND forum {$forumidin} AND groupid {$groupidin}";
 206              $discussionsparams = ['courseid' => $this->courseid];
 207              $discussionsparams += $forumidparams + $groupidparams;
 208  
 209              $discussionids = $DB->get_fieldset_select('forum_discussions', 'DISTINCT id', $discussionswhere, $discussionsparams);
 210  
 211              foreach ($discussionids as $discussionid) {
 212                  $this->discussionids[] = ['discid' => $discussionid];
 213              }
 214          }
 215      }
 216  
 217      /**
 218       * Prepares from date, to date and button text.
 219       * Empty data will default to a disabled filter with today's date.
 220       *
 221       * @param array $datefromdata From date selected for filtering, and whether the filter is enabled.
 222       * @param array $datetodata To date selected for filtering, and whether the filter is enabled.
 223       * @return void.
 224       */
 225      private function prepare_dates_data(array $datefromdata, array $datetodata): void {
 226          $timezone = \core_date::get_user_timezone_object();
 227          $calendartype = \core_calendar\type_factory::get_calendar_instance();
 228          $timestamptoday = time();
 229          $datetoday  = $calendartype->timestamp_to_date_array($timestamptoday, $timezone);
 230  
 231          // Prepare date/enabled data.
 232          if (empty($datefromdata['enabled'])) {
 233              $fromdate = $datetoday;
 234              $fromtimestamp = $timestamptoday;
 235              $fromenabled = false;
 236          } else {
 237              $fromdate = $calendartype->timestamp_to_date_array($datefromdata['timestamp'], $timezone);
 238              $fromtimestamp = $datefromdata['timestamp'];
 239              $fromenabled = true;
 240          }
 241  
 242          if (empty($datetodata['enabled'])) {
 243              $todate = $datetoday;
 244              $totimestamp = $timestamptoday;
 245              $toenabled = false;
 246          } else {
 247              $todate = $calendartype->timestamp_to_date_array($datetodata['timestamp'], $timezone);
 248              $totimestamp = $datetodata['timestamp'];
 249              $toenabled = true;
 250          }
 251  
 252          $this->datesdata = [
 253              'from' => [
 254                  'day'       => $fromdate['mday'],
 255                  'month'     => $fromdate['mon'],
 256                  'year'      => $fromdate['year'],
 257                  'timestamp' => $fromtimestamp,
 258                  'enabled'   => $fromenabled,
 259              ],
 260              'to' => [
 261                  'day'       => $todate['mday'],
 262                  'month'     => $todate['mon'],
 263                  'year'      => $todate['year'],
 264                  'timestamp' => $totimestamp,
 265                  'enabled'   => $toenabled,
 266              ],
 267          ];
 268  
 269          // Prepare button string data.
 270          $displayformat = get_string('strftimedatemonthabbr', 'langconfig');
 271          $fromdatestring = $calendartype->timestamp_to_date_string($fromtimestamp, $displayformat, $timezone, true, true);
 272          $todatestring = $calendartype->timestamp_to_date_string($totimestamp, $displayformat, $timezone, true, true);
 273  
 274          if ($fromenabled && $toenabled) {
 275              $datestrings = [
 276                  'datefrom' => $fromdatestring,
 277                  'dateto'   => $todatestring,
 278              ];
 279              $this->datesbuttontext = get_string('filter:datesfromto', 'forumreport_summary', $datestrings);
 280          } else if ($fromenabled) {
 281              $this->datesbuttontext = get_string('filter:datesfrom', 'forumreport_summary', $fromdatestring);
 282          } else if ($toenabled) {
 283              $this->datesbuttontext = get_string('filter:datesto', 'forumreport_summary', $todatestring);
 284          } else {
 285              $this->datesbuttontext = get_string('filter:datesname', 'forumreport_summary');
 286          }
 287      }
 288  
 289      /**
 290       * Export data for use as the context of a mustache template.
 291       *
 292       * @param renderer_base $renderer The renderer to be used to display report filters.
 293       * @return array Data in a format compatible with a mustache template.
 294       */
 295      public function export_for_template(renderer_base $renderer): stdClass {
 296          $output = new stdClass();
 297  
 298          // Set formaction URL.
 299          $output->actionurl = $this->actionurl->out(false);
 300  
 301          // Set groups filter data.
 302          if (!empty($this->groupsavailable)) {
 303              $output->hasgroups = true;
 304  
 305              $groupscount = count($this->groupsselected);
 306  
 307              if (count($this->groupsavailable) <= $groupscount) {
 308                  $output->filtergroupsname = get_string('filter:groupscountall', 'forumreport_summary');
 309              } else if (!empty($this->groupsselected)) {
 310                  $output->filtergroupsname = get_string('filter:groupscountnumber', 'forumreport_summary', $groupscount);
 311              } else {
 312                  $output->filtergroupsname = get_string('filter:groupsname', 'forumreport_summary');
 313              }
 314  
 315              // Set groups filter.
 316              $groupsdata = [];
 317  
 318              foreach ($this->groupsavailable as $groupid => $groupname) {
 319                  $groupsdata[] = [
 320                      'groupid' => $groupid,
 321                      'groupname' => $groupname,
 322                      'checked' => in_array($groupid, $this->groupsselected),
 323                  ];
 324              }
 325  
 326              $output->filtergroups = $groupsdata;
 327          } else {
 328              $output->hasgroups = false;
 329          }
 330  
 331          // Set discussion IDs for use by export links (always included, as it will be empty if not required).
 332          $output->discussionids = $this->discussionids;
 333  
 334          // Set date button and generate dates popover mform.
 335          $datesformdata = [];
 336  
 337          if ($this->datesdata['from']['enabled']) {
 338              $datesformdata['filterdatefrompopover'] = $this->datesdata['from'];
 339          }
 340  
 341          if ($this->datesdata['to']['enabled']) {
 342              $datesformdata['filterdatetopopover'] = $this->datesdata['to'];
 343          }
 344  
 345          $output->filterdatesname = $this->datesbuttontext;
 346          $datesform = new forumreport_summary\form\dates_filter_form();
 347          $datesform->set_data($datesformdata);
 348          $output->filterdatesform = $datesform->render();
 349  
 350           // Set dates filter data within filters form.
 351          $disableddate = [
 352              'day' => '',
 353              'month' => '',
 354              'year' => '',
 355              'enabled' => '0',
 356          ];
 357          $datefromdata = ['type' => 'from'] + ($this->datesdata['from']['enabled'] ? $this->datesdata['from'] : $disableddate);
 358          $datetodata = ['type' => 'to'] + ($this->datesdata['to']['enabled'] ? $this->datesdata['to'] : $disableddate);
 359          $output->filterdatesdata = [$datefromdata, $datetodata];
 360  
 361          return $output;
 362      }
 363  }