Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * Class picture field for database activity
19
 *
20
 * @package    datafield_picture
21
 * @copyright  2005 Martin Dougiamas
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
class data_field_picture extends data_field_base {
26
    var $type = 'picture';
27
    var $previewwidth  = 50;
28
    var $previewheight = 50;
29
 
30
    public function supports_preview(): bool {
31
        return true;
32
    }
33
 
34
    public function get_data_content_preview(int $recordid): stdClass {
35
        return (object)[
36
            'id' => 0,
37
            'fieldid' => $this->field->id,
38
            'recordid' => $recordid,
39
            'content' => 'datafield_picture/preview',
40
            'content1' => get_string('sample', 'datafield_picture'),
41
            'content2' => null,
42
            'content3' => null,
43
            'content4' => null,
44
        ];
45
    }
46
 
47
    function display_add_field($recordid = 0, $formdata = null) {
48
        global $CFG, $DB, $OUTPUT, $USER, $PAGE;
49
 
50
        // Necessary for the constants used in args.
51
        require_once($CFG->dirroot . '/repository/lib.php');
52
 
53
        $file        = false;
54
        $content     = false;
55
        $alttext     = '';
56
        $itemid = null;
57
        $fs = get_file_storage();
58
 
59
        if ($formdata) {
60
            $fieldname = 'field_' . $this->field->id . '_file';
61
            $itemid = clean_param($formdata->$fieldname, PARAM_INT);
62
            $fieldname = 'field_' . $this->field->id . '_alttext';
63
            if (isset($formdata->$fieldname)) {
64
                $alttext = $formdata->$fieldname;
65
            }
66
        } else if ($recordid) {
67
            if (!$content = $DB->get_record('data_content', array('fieldid' => $this->field->id, 'recordid' => $recordid))) {
68
                // Quickly make one now!
69
                $content = new stdClass();
70
                $content->fieldid  = $this->field->id;
71
                $content->recordid = $recordid;
72
                $id = $DB->insert_record('data_content', $content);
73
                $content = $DB->get_record('data_content', array('id' => $id));
74
            }
75
            file_prepare_draft_area($itemid, $this->context->id, 'mod_data', 'content', $content->id);
76
            if (!empty($content->content)) {
77
                if ($file = $fs->get_file($this->context->id, 'mod_data', 'content', $content->id, '/', $content->content)) {
78
                    $usercontext = context_user::instance($USER->id);
79
 
80
                    if ($thumbfile = $fs->get_file($usercontext->id, 'user', 'draft', $itemid, '/', 'thumb_'.$content->content)) {
81
                        $thumbfile->delete();
82
                    }
83
                }
84
            }
85
            $alttext = $content->content1;
86
        } else {
87
            $itemid = file_get_unused_draft_itemid();
88
        }
89
        $str = '<div title="' . s($this->field->description) . '">';
90
        $str .= '<fieldset><legend><span class="accesshide">'.s($this->field->name);
91
 
92
        if ($this->field->required) {
93
            $str .= '&nbsp;' . get_string('requiredelement', 'form') . '</span></legend>';
94
            $image = $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
95
            $str .= html_writer::div($image, 'inline-req');
96
        } else {
97
            $str .= '</span></legend>';
98
        }
99
        $str .= '<noscript>';
100
        if ($file) {
101
            $src = file_encode_url($CFG->wwwroot.'/pluginfile.php/', $this->context->id.'/mod_data/content/'.$content->id.'/'.$file->get_filename());
102
            $str .= '<img width="'.s($this->previewwidth).'" height="'.s($this->previewheight).'" src="'.$src.'" alt="" />';
103
        }
104
        $str .= '</noscript>';
105
 
106
        $options = new stdClass();
107
        $options->maxbytes  = $this->field->param3;
108
        $options->maxfiles  = 1; // Only one picture permitted.
109
        $options->itemid    = $itemid;
110
        $options->accepted_types = array('web_image');
111
        $options->return_types = FILE_INTERNAL;
112
        $options->context = $PAGE->context;
113
        if (!empty($file)) {
114
            $options->filename = $file->get_filename();
115
            $options->filepath = '/';
116
        }
117
 
118
        $fm = new form_filemanager($options);
119
        // Print out file manager.
120
 
121
        $output = $PAGE->get_renderer('core', 'files');
122
        $str .= '<div class="mod-data-input">';
123
        $str .= $output->render($fm);
124
 
125
        $str .= '<div class="mdl-left">';
126
        $str .= '<input type="hidden" name="field_' . $this->field->id . '_file" value="' . s($itemid) . '" />';
127
        $str .= '<label for="field_' . $this->field->id . '_alttext">' .
128
                get_string('alttext', 'data') .
129
                '</label>&nbsp;<input type="text" class="form-control" name="field_' .
130
                $this->field->id . '_alttext" id="field_' . $this->field->id . '_alttext" value="' . s($alttext) . '" />';
131
        $str .= '</div>';
132
        $str .= '</div>';
133
 
134
        $str .= '</fieldset>';
135
        $str .= '</div>';
136
 
137
        return $str;
138
    }
139
 
140
    /**
141
     * Validate the image field type parameters.
142
     *
143
     * This will check for valid numeric values in the width and height fields.
144
     *
145
     * @param stdClass $fieldinput the field input data
146
     * @return array array of error messages if width or height parameters are not numeric
147
     * @throws coding_exception
148
     */
149
    public function validate(stdClass $fieldinput): array {
150
        $errors = [];
151
        // These are the params we have to check if they are numeric, because they represent width and height of the image
152
        // in single and list view.
153
        $widthandheightparams = ['param1', 'param2', 'param4', 'param5'];
154
 
155
        foreach ($widthandheightparams as $param) {
156
            if (!empty($fieldinput->$param) && !is_numeric($fieldinput->$param)) {
157
                $errors[$param] = get_string('error_invalid' . $param, 'datafield_picture');
158
            }
159
        }
160
        return $errors;
161
    }
162
 
163
    // TODO delete this function and instead subclass data_field_file - see MDL-16493
164
 
165
    function get_file($recordid, $content=null) {
166
        global $DB;
167
        if (empty($content)) {
168
            if (!$content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
169
                return null;
170
            }
171
        }
172
        $fs = get_file_storage();
173
        if (!$file = $fs->get_file($this->context->id, 'mod_data', 'content', $content->id, '/', $content->content)) {
174
            return null;
175
        }
176
 
177
        return $file;
178
    }
179
 
180
    function display_search_field($value = '') {
181
        return '<label class="accesshide" for="f_' . $this->field->id . '">' . get_string('fieldname', 'data') . '</label>' .
182
               '<input type="text" size="16" id="f_' . $this->field->id . '" name="f_' . $this->field->id . '" ' .
183
               'value="' . s($value) . '" class="form-control"/>';
184
    }
185
 
186
    public function parse_search_field($defaults = null) {
187
        $param = 'f_'.$this->field->id;
188
        if (empty($defaults[$param])) {
189
            $defaults = array($param => '');
190
        }
191
        return optional_param($param, $defaults[$param], PARAM_NOTAGS);
192
    }
193
 
194
    function generate_sql($tablealias, $value) {
195
        global $DB;
196
 
197
        static $i=0;
198
        $i++;
199
        $name = "df_picture_$i";
200
        return array(" ({$tablealias}.fieldid = {$this->field->id} AND ".$DB->sql_like("{$tablealias}.content", ":$name", false).") ", array($name=>"%$value%"));
201
    }
202
 
203
    function display_browse_field($recordid, $template) {
204
        global $OUTPUT;
205
 
206
        $content = $this->get_data_content($recordid);
207
 
208
        if (!$content || empty($content->content)) {
209
            return '';
210
        }
211
 
212
        $alt   = $content->content1;
213
        $title = $alt;
214
 
215
        $width  = $this->field->param1 ? ' width="' . s($this->field->param1) . '" ' : ' ';
216
        $height = $this->field->param2 ? ' height="' . s($this->field->param2) . '" ' : ' ';
217
 
218
        if ($this->preview) {
219
            $imgurl = $OUTPUT->image_url('sample', 'datafield_picture');
220
            return '<img ' . $width . $height . ' src="' . $imgurl . '" alt="' . s($alt) . '" class="list_picture"/>';
221
        }
222
 
223
        if ($template == 'listtemplate') {
224
            $filename = 'thumb_' . $content->content;
225
            // Thumbnails are already converted to the correct width and height.
226
            $width = '';
227
            $height = '';
228
            $url = new moodle_url('/mod/data/view.php', ['d' => $this->field->dataid, 'rid' => $recordid]);
229
        } else {
230
            $filename = $content->content;
231
            $url = null;
232
        }
233
        $imgurl = moodle_url::make_pluginfile_url($this->context->id, 'mod_data', 'content', $content->id, '/', $filename);
234
 
235
        if (!$url) {
236
            $url = $imgurl;
237
        }
238
        $img = '<img ' . $width . $height . ' src="' . $imgurl->out() . '" alt="' . s($alt) .
239
            '" title="' . s($title) . '" class="list_picture"/>';
240
        return '<a class="data-field-link" href="' . $url->out() . '">' . $img . '</a>';
241
    }
242
 
243
    function update_field() {
244
        global $DB, $OUTPUT;
245
 
246
        // Get the old field data so that we can check whether the thumbnail dimensions have changed
247
        $oldfield = $DB->get_record('data_fields', array('id'=>$this->field->id));
248
        $DB->update_record('data_fields', $this->field);
249
 
250
        // Have the thumbnail dimensions changed?
251
        if ($oldfield && ($oldfield->param4 != $this->field->param4 || $oldfield->param5 != $this->field->param5)) {
252
            // Check through all existing records and update the thumbnail
253
            if ($contents = $DB->get_records('data_content', array('fieldid'=>$this->field->id))) {
254
                $fs = get_file_storage();
255
                if (count($contents) > 20) {
256
                    echo $OUTPUT->notification(get_string('resizingimages', 'data'), 'notifysuccess');
257
                    echo "\n\n";
258
                    // To make sure that ob_flush() has the desired effect
259
                    ob_flush();
260
                }
261
                foreach ($contents as $content) {
262
                    if (!$file = $fs->get_file($this->context->id, 'mod_data', 'content', $content->id, '/', $content->content)) {
263
                        continue;
264
                    }
265
                    if ($thumbfile = $fs->get_file($this->context->id, 'mod_data', 'content', $content->id, '/', 'thumb_'.$content->content)) {
266
                        $thumbfile->delete();
267
                    }
268
                    core_php_time_limit::raise(300);
269
                    // Might be slow!
270
                    $this->update_thumbnail($content, $file);
271
                }
272
            }
273
        }
274
        return true;
275
    }
276
 
277
    function update_content($recordid, $value, $name='') {
278
        global $CFG, $DB, $USER;
279
 
280
        // Should always be available since it is set by display_add_field before initializing the draft area.
281
        $content = $DB->get_record('data_content', array('fieldid' => $this->field->id, 'recordid' => $recordid));
282
        if (!$content) {
283
            $content = (object)array('fieldid' => $this->field->id, 'recordid' => $recordid);
284
            $content->id = $DB->insert_record('data_content', $content);
285
        }
286
 
287
        $names = explode('_', $name);
288
        switch ($names[2]) {
289
            case 'file':
290
                $fs = get_file_storage();
291
                file_save_draft_area_files($value, $this->context->id, 'mod_data', 'content', $content->id);
292
                $usercontext = context_user::instance($USER->id);
293
                $files = $fs->get_area_files(
294
                    $this->context->id,
295
                    'mod_data', 'content',
296
                    $content->id,
297
                    'itemid, filepath, filename',
298
                    false);
299
 
300
                // We expect no or just one file (maxfiles = 1 option is set for the form_filemanager).
301
                if (count($files) == 0) {
302
                    $content->content = null;
303
                } else {
304
                    $file = array_values($files)[0];
305
 
306
                    if (count($files) > 1) {
307
                        // This should not happen with a consistent database. Inform admins/developers about the inconsistency.
308
                        debugging('more then one file found in mod_data instance {$this->data->id} picture field (field id: {$this->field->id}) area during update data record {$recordid} (content id: {$content->id})', DEBUG_NORMAL);
309
                    }
310
 
311
                    if ($file->get_imageinfo() === false) {
312
                        $url = new moodle_url('/mod/data/edit.php', array('d' => $this->field->dataid));
313
                        redirect($url, get_string('invalidfiletype', 'error', $file->get_filename()));
314
                    }
315
                    $content->content = $file->get_filename();
316
                    $this->update_thumbnail($content, $file);
317
                }
318
                $DB->update_record('data_content', $content);
319
 
320
                break;
321
 
322
            case 'alttext':
323
                // only changing alt tag
324
                $content->content1 = clean_param($value, PARAM_NOTAGS);
325
                $DB->update_record('data_content', $content);
326
                break;
327
 
328
            default:
329
                break;
330
        }
331
    }
332
 
333
    function update_thumbnail($content, $file) {
334
        // (Re)generate thumbnail image according to the dimensions specified in the field settings.
335
        // If thumbnail width and height are BOTH not specified then no thumbnail is generated, and
336
        // additionally an attempted delete of the existing thumbnail takes place.
337
        $fs = get_file_storage();
338
        $filerecord = [
339
            'contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(),
340
            'itemid' => $file->get_itemid(), 'filepath' => $file->get_filepath(),
341
            'filename' => 'thumb_' . $file->get_filename(), 'userid' => $file->get_userid()
342
        ];
343
        try {
344
            // This may fail for various reasons.
345
            $newwidth = isset($this->field->param4) ? (int) $this->field->param4 : null;
346
            $newheight = isset($this->field->param5) ? (int) $this->field->param5 : null;
347
            $fs->convert_image($filerecord, $file, $newwidth, $newheight, true);
348
            return true;
349
        } catch (Exception $e) {
350
            debugging($e->getMessage());
351
            return false;
352
        }
353
    }
354
 
355
    /**
356
     * Here we export the text value of a picture field which is the filename of the exported picture.
357
     *
358
     * @param stdClass $record the record which is being exported
359
     * @return string the value which will be stored in the exported file for this field
360
     */
361
    public function export_text_value(stdClass $record): string {
362
        return !empty($record->content) ? $record->content : '';
363
    }
364
 
365
    /**
366
     * Specifies that this field type supports the export of files.
367
     *
368
     * @return bool true which means that file export is being supported by this field type
369
     */
370
    public function file_export_supported(): bool {
371
        return true;
372
    }
373
 
374
    /**
375
     * Exports the file content for file export.
376
     *
377
     * @param stdClass $record the data content record the file belongs to
378
     * @return null|string The file content of the stored file or null if no file should be exported for this record
379
     */
380
    public function export_file_value(stdClass $record): null|string {
381
        $file = $this->get_file($record->id);
382
        return $file ? $file->get_content() : null;
383
    }
384
 
385
    /**
386
     * Specifies that this field type supports the import of files.
387
     *
388
     * @return bool true which means that file import is being supported by this field type
389
     */
390
    public function file_import_supported(): bool {
391
        return true;
392
    }
393
 
394
    /**
395
     * Provides the necessary code for importing a file when importing the content of a mod_data instance.
396
     *
397
     * @param int $contentid the id of the mod_data content record
398
     * @param string $filecontent the content of the file to import as string
399
     * @param string $filename the filename the imported file should get
400
     * @return void
401
     */
402
    public function import_file_value(int $contentid, string $filecontent, string $filename): void {
403
        $filerecord = [
404
            'contextid' => $this->context->id,
405
            'component' => 'mod_data',
406
            'filearea' => 'content',
407
            'itemid' => $contentid,
408
            'filepath' => '/',
409
            'filename' => $filename,
410
        ];
411
        $fs = get_file_storage();
412
        $file = $fs->create_file_from_string($filerecord, $filecontent);
413
        $this->update_thumbnail(null, $file);
414
    }
415
 
416
    function file_ok($path) {
417
        return true;
418
    }
419
 
420
    /**
421
     * Custom notempty function
422
     *
423
     * @param string $value
424
     * @param string $name
425
     * @return bool
426
     */
427
    function notemptyfield($value, $name) {
428
        global $USER;
429
 
430
        $names = explode('_', $name);
431
        if ($names[2] == 'file') {
432
            $usercontext = context_user::instance($USER->id);
433
            $fs = get_file_storage();
434
            $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $value);
435
            return count($files) >= 2;
436
        }
437
        return false;
438
    }
439
 
440
    /**
441
     * Return the plugin configs for external functions.
442
     *
443
     * @return array the list of config parameters
444
     * @since Moodle 3.3
445
     */
446
    public function get_config_for_external() {
447
        // Return all the config parameters.
448
        $configs = [];
449
        for ($i = 1; $i <= 10; $i++) {
450
            $configs["param$i"] = $this->field->{"param$i"};
451
        }
452
        return $configs;
453
    }
454
 
455
    public function get_field_params(): array {
456
        global $DB, $CFG;
457
 
458
        $data = parent::get_field_params();
459
 
460
        $course = $DB->get_record('course', ['id' => $this->data->course]);
461
        $filesizes = get_max_upload_sizes($CFG->maxbytes, $course->maxbytes, 0, $this->field->param3);
462
 
463
        foreach ($filesizes as $value => $name) {
464
            if (!((isset($this->field->param3) && $value == $this->field->param3))) {
465
                $data['options'][] = ['name' => $name, 'value' => $value, 'selected' => 0];
466
            } else {
467
                $data['options'][] = ['name' => $name, 'value' => $value, 'selected' => 1];
468
            }
469
        }
470
 
471
        return $data;
472
    }
473
}