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  ///////////////////////////////////////////////////////////////////////////
   3  //                                                                       //
   4  // NOTICE OF COPYRIGHT                                                   //
   5  //                                                                       //
   6  // Moodle - Modular Object-Oriented Dynamic Learning Environment         //
   7  //          http://moodle.org                                            //
   8  //                                                                       //
   9  // Copyright (C) 1999-onwards Moodle Pty Ltd  http://moodle.com          //
  10  //                                                                       //
  11  // This program is free software; you can redistribute it and/or modify  //
  12  // it under the terms of the GNU General Public License as published by  //
  13  // the Free Software Foundation; either version 2 of the License, or     //
  14  // (at your option) any later version.                                   //
  15  //                                                                       //
  16  // This program is distributed in the hope that it will be useful,       //
  17  // but WITHOUT ANY WARRANTY; without even the implied warranty of        //
  18  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
  19  // GNU General Public License for more details:                          //
  20  //                                                                       //
  21  //          http://www.gnu.org/copyleft/gpl.html                         //
  22  //                                                                       //
  23  ///////////////////////////////////////////////////////////////////////////
  24  
  25  class data_field_multimenu extends data_field_base {
  26  
  27      var $type = 'multimenu';
  28      /**
  29       * priority for globalsearch indexing
  30       *
  31       * @var int
  32       * */
  33      protected static $priority = self::LOW_PRIORITY;
  34  
  35      public function supports_preview(): bool {
  36          return true;
  37      }
  38  
  39      public function get_data_content_preview(int $recordid): stdClass {
  40          $options = explode("\n", $this->field->param1);
  41          $options = array_map('trim', $options);
  42          $selected = $options[$recordid % count($options)];
  43          $selected .= '##' . $options[($recordid + 1) % count($options)];
  44          return (object)[
  45              'id' => 0,
  46              'fieldid' => $this->field->id,
  47              'recordid' => $recordid,
  48              'content' => $selected,
  49              'content1' => null,
  50              'content2' => null,
  51              'content3' => null,
  52              'content4' => null,
  53          ];
  54      }
  55  
  56      function display_add_field($recordid = 0, $formdata = null) {
  57          global $DB, $OUTPUT;
  58  
  59          if ($formdata) {
  60              $fieldname = 'field_' . $this->field->id;
  61              if (isset($formdata->$fieldname)) {
  62                  $content = $formdata->$fieldname;
  63              } else {
  64                  $content = array();
  65              }
  66          } else if ($recordid) {
  67              $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
  68              $content = explode('##', $content);
  69          } else {
  70              $content = array();
  71          }
  72  
  73          $str = '<div title="'.s($this->field->description).'">';
  74          $str .= '<input name="field_' . $this->field->id . '[xxx]" type="hidden" value="xxx"/>'; // hidden field - needed for empty selection
  75  
  76          $str .= '<label for="field_' . $this->field->id . '">';
  77          $str .= '<legend><span class="accesshide">' . $this->field->name;
  78  
  79          if ($this->field->required) {
  80              $str .= '&nbsp;' . get_string('requiredelement', 'form') . '</span></legend>';
  81              $str .= '<div class="inline-req">';
  82              $str .= $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
  83              $str .= '</div>';
  84          } else {
  85              $str .= '</span></legend>';
  86          }
  87          $str .= '</label>';
  88          $str .= '<select name="field_' . $this->field->id . '[]" id="field_' . $this->field->id . '"';
  89          $str .= ' multiple="multiple" class="mod-data-input form-control">';
  90  
  91          foreach (explode("\n", $this->field->param1) as $option) {
  92              $option = trim($option);
  93              $str .= '<option value="' . s($option) . '"';
  94  
  95              if (in_array($option, $content)) {
  96                  // Selected by user.
  97                  $str .= ' selected = "selected"';
  98              }
  99  
 100              $str .= '>';
 101              $str .= $option . '</option>';
 102          }
 103          $str .= '</select>';
 104          $str .= '</div>';
 105  
 106          return $str;
 107      }
 108  
 109      function display_search_field($value = '') {
 110          global $CFG, $DB;
 111  
 112          if (is_array($value)){
 113              $content     = $value['selected'];
 114              $allrequired = $value['allrequired'] ? true : false;
 115          } else {
 116              $content     = array();
 117              $allrequired = false;
 118          }
 119  
 120          static $c = 0;
 121  
 122          $str = '<label class="accesshide" for="f_' . $this->field->id . '">' . $this->field->name . '</label>';
 123          $str .= '<select id="f_'.$this->field->id.'" name="f_'.$this->field->id.'[]" multiple="multiple" class="form-control">';
 124  
 125          // display only used options
 126          $varcharcontent =  $DB->sql_compare_text('content', 255);
 127          $sql = "SELECT DISTINCT $varcharcontent AS content
 128                    FROM {data_content}
 129                   WHERE fieldid=? AND content IS NOT NULL";
 130  
 131          $usedoptions = array();
 132          if ($used = $DB->get_records_sql($sql, array($this->field->id))) {
 133              foreach ($used as $data) {
 134                  $valuestr = $data->content;
 135                  if ($valuestr === '') {
 136                      continue;
 137                  }
 138                  $values = explode('##', $valuestr);
 139                  foreach ($values as $value) {
 140                      $usedoptions[$value] = $value;
 141                  }
 142              }
 143          }
 144  
 145          $found = false;
 146          foreach (explode("\n",$this->field->param1) as $option) {
 147              $option = trim($option);
 148              if (!isset($usedoptions[$option])) {
 149                  continue;
 150              }
 151              $found = true;
 152              $str .= '<option value="' . s($option) . '"';
 153  
 154              if (in_array($option, $content)) {
 155                  // Selected by user.
 156                  $str .= ' selected = "selected"';
 157              }
 158              $str .= '>' . $option . '</option>';
 159          }
 160          if (!$found) {
 161              // oh, nothing to search for
 162              return '';
 163          }
 164  
 165          $str .= '</select>';
 166  
 167          $str .= html_writer::checkbox('f_'.$this->field->id.'_allreq', null, $allrequired,
 168              get_string('selectedrequired', 'data'), array('class' => 'mr-1'));
 169  
 170          return $str;
 171  
 172      }
 173  
 174      public function parse_search_field($defaults = null) {
 175          $paramselected = 'f_'.$this->field->id;
 176          $paramallrequired = 'f_'.$this->field->id.'_allreq';
 177  
 178          if (empty($defaults[$paramselected])) { // One empty means the other ones are empty too.
 179              $defaults = array($paramselected => array(), $paramallrequired => 0);
 180          }
 181  
 182          $selected    = optional_param_array($paramselected, $defaults[$paramselected], PARAM_NOTAGS);
 183          $allrequired = optional_param($paramallrequired, $defaults[$paramallrequired], PARAM_BOOL);
 184  
 185          if (empty($selected)) {
 186              // no searching
 187              return '';
 188          }
 189          return array('selected'=>$selected, 'allrequired'=>$allrequired);
 190      }
 191  
 192      function generate_sql($tablealias, $value) {
 193          global $DB;
 194  
 195          static $i=0;
 196          $i++;
 197          $name = "df_multimenu_{$i}_";
 198          $params = array();
 199          $varcharcontent = $DB->sql_compare_text("{$tablealias}.content", 255);
 200  
 201          $allrequired = $value['allrequired'];
 202          $selected    = $value['selected'];
 203  
 204          if ($selected) {
 205              $conditions = array();
 206              $j=0;
 207              foreach ($selected as $sel) {
 208                  $j++;
 209                  $xname = $name.$j;
 210                  $likesel = str_replace('%', '\%', $sel);
 211                  $likeselsel = str_replace('_', '\_', $likesel);
 212                  $conditions[] = "({$tablealias}.fieldid = {$this->field->id} AND ({$varcharcontent} = :{$xname}a
 213                                                                                 OR {$tablealias}.content LIKE :{$xname}b
 214                                                                                 OR {$tablealias}.content LIKE :{$xname}c
 215                                                                                 OR {$tablealias}.content LIKE :{$xname}d))";
 216                  $params[$xname.'a'] = $sel;
 217                  $params[$xname.'b'] = "$likesel##%";
 218                  $params[$xname.'c'] = "%##$likesel";
 219                  $params[$xname.'d'] = "%##$likesel##%";
 220              }
 221              if ($allrequired) {
 222                  return array(" (".implode(" AND ", $conditions).") ", $params);
 223              } else {
 224                  return array(" (".implode(" OR ", $conditions).") ", $params);
 225              }
 226          } else {
 227              return array(" ", array());
 228          }
 229      }
 230  
 231      function update_content($recordid, $value, $name='') {
 232          global $DB;
 233  
 234          $content = new stdClass();
 235          $content->fieldid  = $this->field->id;
 236          $content->recordid = $recordid;
 237          $content->content  = $this->format_data_field_multimenu_content($value);
 238  
 239          if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
 240              $content->id = $oldcontent->id;
 241              return $DB->update_record('data_content', $content);
 242          } else {
 243              return $DB->insert_record('data_content', $content);
 244          }
 245      }
 246  
 247      function format_data_field_multimenu_content($content) {
 248          if (!is_array($content)) {
 249              return NULL;
 250          }
 251          $options = explode("\n", $this->field->param1);
 252          $options = array_map('trim', $options);
 253  
 254          $vals = array();
 255          foreach ($content as $key=>$val) {
 256              if ($key === 'xxx') {
 257                  continue;
 258              }
 259              if (!in_array($val, $options)) {
 260                  continue;
 261              }
 262              $vals[] = $val;
 263          }
 264  
 265          if (empty($vals)) {
 266              return NULL;
 267          }
 268  
 269          return implode('##', $vals);
 270      }
 271  
 272  
 273      function display_browse_field($recordid, $template) {
 274          $content = $this->get_data_content($recordid);
 275          if (!$content || empty($content->content)) {
 276              return '';
 277          }
 278          $options = explode("\n", $this->field->param1);
 279          $options = array_map('trim', $options);
 280  
 281          $contentarray = explode('##', $content->content);
 282          $str = '';
 283          foreach ($contentarray as $line) {
 284              if (!in_array($line, $options)) {
 285                  // Hmm, looks like somebody edited the field definition.
 286                  continue;
 287              }
 288              $str .= $line . "<br />\n";
 289          }
 290          return $str;
 291      }
 292  
 293      /**
 294       * Check if a field from an add form is empty
 295       *
 296       * @param mixed $value
 297       * @param mixed $name
 298       * @return bool
 299       */
 300      function notemptyfield($value, $name) {
 301          unset($value['xxx']);
 302          return !empty($value);
 303      }
 304  
 305      /**
 306       * Returns the presentable string value for a field content.
 307       *
 308       * The returned string should be plain text.
 309       *
 310       * @param stdClass $content
 311       * @return string
 312       */
 313      public static function get_content_value($content) {
 314          $arr = explode('##', $content->content);
 315  
 316          $strvalue = '';
 317          foreach ($arr as $a) {
 318              $strvalue .= $a . ' ';
 319          }
 320  
 321          return trim($strvalue, "\r\n ");
 322      }
 323  
 324      /**
 325       * Return the plugin configs for external functions.
 326       *
 327       * @return array the list of config parameters
 328       * @since Moodle 3.3
 329       */
 330      public function get_config_for_external() {
 331          // Return all the config parameters.
 332          $configs = [];
 333          for ($i = 1; $i <= 10; $i++) {
 334              $configs["param$i"] = $this->field->{"param$i"};
 335          }
 336          return $configs;
 337      }
 338  }