See Release Notes
Long Term Support Release
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_latlong extends data_field_base { 26 var $type = 'latlong'; 27 28 // This is an array of URL schemes for linking out to services, using the float values of lat and long. 29 // In each scheme, the special markers @lat@ and @long@ will be replaced by the float values. 30 // The config options for the field store each service name that should be displayed, in a comma-separated 31 // field. Therefore please DO NOT include commas in the service names if you are adding extra services. 32 33 // Parameter data used: 34 // "param1" is a comma-separated list of the linkout service names that are enabled for this instance 35 // "param2" indicates the label that will be used in generating Google Earth KML files: -1 for item #, -2 for lat/long, positive number for the (text) field to use. 36 37 var $linkoutservices = array( 38 "Google Maps" => "http://maps.google.com/maps?q=@lat@,+@long@&iwloc=A&hl=en", 39 "Google Earth" => "@wwwroot@/mod/data/field/latlong/kml.php?d=@dataid@&fieldid=@fieldid@&rid=@recordid@", 40 "Geabios" => "http://www.geabios.com/html/services/maps/PublicMap.htm?lat=@lat@&lon=@long@&fov=0.3&title=Moodle%20data%20item", 41 "OpenStreetMap" => "http://www.openstreetmap.org/index.html?lat=@lat@&lon=@long@&zoom=11", 42 "Multimap" => "http://www.multimap.com/map/browse.cgi?scale=200000&lon=@long@&lat=@lat@&icon=x" 43 ); 44 // Other map sources listed at http://kvaleberg.com/extensions/mapsources/index.php?params=51_30.4167_N_0_7.65_W_region:earth 45 46 public function supports_preview(): bool { 47 return true; 48 } 49 50 public function get_data_content_preview(int $recordid): stdClass { 51 return (object)[ 52 'id' => 0, 53 'fieldid' => $this->field->id, 54 'recordid' => $recordid, 55 'content' => 41.391205, 56 'content1' => 2.163873, 57 'content2' => null, 58 'content3' => null, 59 'content4' => null, 60 ]; 61 } 62 63 function display_add_field($recordid = 0, $formdata = null) { 64 global $CFG, $DB, $OUTPUT; 65 66 $lat = ''; 67 $long = ''; 68 if ($formdata) { 69 $fieldname = 'field_' . $this->field->id . '_0'; 70 $lat = $formdata->$fieldname; 71 $fieldname = 'field_' . $this->field->id . '_1'; 72 $long = $formdata->$fieldname; 73 } else if ($recordid) { 74 if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) { 75 $lat = $content->content; 76 $long = $content->content1; 77 } 78 } 79 $str = '<div title="'.s($this->field->description).'">'; 80 $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>'; 81 $str .= '<table class="form-inline"><tr><td align="right">'; 82 $classes = 'mod-data-input form-control-static'; 83 $str .= '<label for="field_'.$this->field->id.'_0" class="' . $classes . '">' . get_string('latitude', 'data'); 84 if ($this->field->required) { 85 $str .= $OUTPUT->pix_icon('req', get_string('requiredelement', 'form')); 86 } 87 $classes = 'form-control mx-1'; 88 $str .= '</label></td><td>'; 89 $str .= '<input class="' . $classes . '" type="text" name="field_'.$this->field->id.'_0" '; 90 $str .= ' id="field_'.$this->field->id.'_0" value="'; 91 $str .= s($lat).'" size="10" />°N</td></tr>'; 92 $classes = 'mod-data-input form-control-static'; 93 $str .= '<tr><td align="right"><label for="field_'.$this->field->id.'_1" class="' . $classes . '">'; 94 $str .= get_string('longitude', 'data'); 95 if ($this->field->required) { 96 $str .= $OUTPUT->pix_icon('req', get_string('requiredelement', 'form')); 97 } 98 $classes = 'form-control mx-1'; 99 $str .= '</label></td><td><input class="' . $classes . '" type="text" '; 100 $str .= 'name="field_'.$this->field->id.'_1" id="field_'.$this->field->id.'_1" value="'; 101 $str .= s($long).'" size="10" />°E</td>'; 102 $str .= '</tr>'; 103 $str .= '</table>'; 104 $str .= '</fieldset>'; 105 $str .= '</div>'; 106 return $str; 107 } 108 109 function display_search_field($value = '') { 110 global $CFG, $DB; 111 112 $varcharlat = $DB->sql_compare_text('content'); 113 $varcharlong= $DB->sql_compare_text('content1'); 114 $latlongsrs = $DB->get_recordset_sql( 115 "SELECT DISTINCT $varcharlat AS la, $varcharlong AS lo 116 FROM {data_content} 117 WHERE fieldid = ? 118 ORDER BY $varcharlat, $varcharlong", array($this->field->id)); 119 120 $options = array(); 121 foreach ($latlongsrs as $latlong) { 122 $latitude = format_float($latlong->la, 4); 123 $longitude = format_float($latlong->lo, 4); 124 if ($latitude && $longitude) { 125 $options[$latlong->la . ',' . $latlong->lo] = $latitude . ' ' . $longitude; 126 } 127 } 128 $latlongsrs->close(); 129 130 $classes = array('class' => 'accesshide'); 131 $return = html_writer::label(get_string('latlong', 'data'), 'menuf_'.$this->field->id, false, $classes); 132 $classes = array('class' => 'custom-select'); 133 $return .= html_writer::select($options, 'f_'.$this->field->id, $value, array('' => get_string('menuchoose', 'data')), 134 $classes); 135 return $return; 136 } 137 138 public function parse_search_field($defaults = null) { 139 $param = 'f_'.$this->field->id; 140 if (empty($defaults[$param])) { 141 $defaults = array($param => ''); 142 } 143 return optional_param($param, $defaults[$param], PARAM_NOTAGS); 144 } 145 146 function generate_sql($tablealias, $value) { 147 global $DB; 148 149 static $i=0; 150 $i++; 151 $name1 = "df_latlong1_$i"; 152 $name2 = "df_latlong2_$i"; 153 $varcharlat = $DB->sql_compare_text("{$tablealias}.content"); 154 $varcharlong= $DB->sql_compare_text("{$tablealias}.content1"); 155 156 157 $latlong[0] = ''; 158 $latlong[1] = ''; 159 $latlong = explode (',', $value, 2); 160 return array(" ({$tablealias}.fieldid = {$this->field->id} AND $varcharlat = :$name1 AND $varcharlong = :$name2) ", 161 array($name1=>$latlong[0], $name2=>$latlong[1])); 162 } 163 164 function display_browse_field($recordid, $template) { 165 global $CFG; 166 167 $content = $this->get_data_content($recordid); 168 if (!$content) { 169 return ''; 170 } 171 172 $lat = $content->content; 173 if (strlen($lat ?? '') < 1) { 174 return ''; 175 } 176 $long = $content->content1; 177 if (strlen($long ?? '') < 1) { 178 return ''; 179 } 180 // We use format_float to display in the regional format. 181 if ($lat < 0) { 182 $compasslat = format_float(-$lat, 4) . '°S'; 183 } else { 184 $compasslat = format_float($lat, 4) . '°N'; 185 } 186 if ($long < 0) { 187 $compasslong = format_float(-$long, 4) . '°W'; 188 } else { 189 $compasslong = format_float($long, 4) . '°E'; 190 } 191 192 // Now let's create the jump-to-services link. 193 $servicesshown = explode(',', $this->field->param1); 194 195 // These are the different things that can be magically inserted into URL schemes. 196 $urlreplacements = array( 197 '@lat@' => $lat, 198 '@long@' => $long, 199 '@wwwroot@' => $CFG->wwwroot, 200 '@contentid@' => $content->id, 201 '@dataid@' => $this->data->id, 202 '@courseid@' => $this->data->course, 203 '@fieldid@' => $content->fieldid, 204 '@recordid@' => $content->recordid, 205 ); 206 207 if (count($servicesshown) == 1 && $servicesshown[0]) { 208 $str = " <a class=\"data-field-link\" href='" 209 . str_replace( 210 array_keys($urlreplacements), 211 array_values($urlreplacements), 212 $this->linkoutservices[$servicesshown[0]] 213 ) . "' title='$servicesshown[0]'>$compasslat $compasslong</a>"; 214 } else if (count($servicesshown) > 1) { 215 $str = '<form id="latlongfieldbrowse" class="data-field-html">'; 216 $str .= "$compasslat, $compasslong\n"; 217 $str .= "<label class='accesshide' for='jumpto'>". get_string('jumpto') ."</label>"; 218 $str .= '<select id="jumpto" name="jumpto" class="custom-select">'; 219 foreach ($servicesshown as $servicename) { 220 // Add a link to a service. 221 $str .= "\n <option value='" 222 . str_replace( 223 array_keys($urlreplacements), 224 array_values($urlreplacements), 225 $this->linkoutservices[$servicename] 226 ) . "'>".htmlspecialchars($servicename, ENT_COMPAT)."</option>"; 227 } 228 // NB! If you are editing this, make sure you don't break the javascript reference "previousSibling" 229 // which allows the "Go" button to refer to the drop-down selector. 230 $str .= '\n</select><input type="button" class="btn ml-1 btn-secondary" value="' . get_string('go'); 231 $str .= '" onclick="if(previousSibling.value){self.location=previousSibling.value}"/>'; 232 $str .= '</form>'; 233 } else { 234 $str = "$compasslat, $compasslong"; 235 } 236 237 return $str; 238 } 239 240 function update_content_import($recordid, $value, $name='') { 241 $values = explode(" ", $value, 2); 242 243 foreach ($values as $index => $value) { 244 $this->update_content($recordid, $value, $name . '_' . $index); 245 } 246 } 247 248 function update_content($recordid, $value, $name='') { 249 global $DB; 250 251 $content = new stdClass(); 252 $content->fieldid = $this->field->id; 253 $content->recordid = $recordid; 254 // When updating these values (which might be region formatted) we should format 255 // the float to allow for a consistent float format in the database. 256 $value = unformat_float($value); 257 $value = trim($value ?? ''); 258 if (strlen($value) > 0) { 259 $value = floatval($value); 260 } else { 261 $value = null; 262 } 263 $names = explode('_', $name); 264 switch ($names[2]) { 265 case 0: 266 // update lat 267 $content->content = $value; 268 break; 269 case 1: 270 // update long 271 $content->content1 = $value; 272 break; 273 default: 274 break; 275 } 276 if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) { 277 $content->id = $oldcontent->id; 278 return $DB->update_record('data_content', $content); 279 } else { 280 return $DB->insert_record('data_content', $content); 281 } 282 } 283 284 function get_sort_sql($fieldname) { 285 global $DB; 286 return $DB->sql_cast_char2real($fieldname, true); 287 } 288 289 function export_text_value($record) { 290 // The content here is from the database and does not require location formating. 291 return sprintf('%01.4f', $record->content) . ' ' . sprintf('%01.4f', $record->content1); 292 } 293 294 /** 295 * Check if a field from an add form is empty 296 * 297 * @param mixed $value 298 * @param mixed $name 299 * @return bool 300 */ 301 function notemptyfield($value, $name) { 302 return isset($value) && !($value == ''); 303 } 304 305 /** 306 * Validate values for this field. 307 * Both the Latitude and the Longitude fields need to be filled in. 308 * 309 * @param array $values The entered values for the lat. and long. 310 * @return string|bool Error message or false. 311 */ 312 public function field_validation($values) { 313 $valuecount = 0; 314 // The lat long class has two values that need to be checked. 315 foreach ($values as $value) { 316 if (isset($value->value) && !($value->value == '')) { 317 $valuecount++; 318 } 319 } 320 // If we have nothing filled in or both filled in then everything is okay. 321 if ($valuecount == 0 || $valuecount == 2) { 322 return false; 323 } 324 // If we get here then only one field has been filled in. 325 return get_string('latlongboth', 'data'); 326 } 327 328 /** 329 * Return the plugin configs for external functions. 330 * 331 * @return array the list of config parameters 332 * @since Moodle 3.3 333 */ 334 public function get_config_for_external() { 335 // Return all the config parameters. 336 $configs = []; 337 for ($i = 1; $i <= 10; $i++) { 338 $configs["param$i"] = $this->field->{"param$i"}; 339 } 340 return $configs; 341 } 342 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body