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 represents a customcert template.
19
 *
20
 * @package    mod_customcert
21
 * @copyright  2016 Mark Nelson <markn@moodle.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace mod_customcert;
26
 
27
/**
28
 * Class represents a customcert template.
29
 *
30
 * @package    mod_customcert
31
 * @copyright  2016 Mark Nelson <markn@moodle.com>
32
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
34
class template {
35
 
36
    /**
37
     * @var int $id The id of the template.
38
     */
39
    protected $id;
40
 
41
    /**
42
     * @var string $name The name of this template
43
     */
44
    protected $name;
45
 
46
    /**
47
     * @var int $contextid The context id of this template
48
     */
49
    protected $contextid;
50
 
51
    /**
52
     * The constructor.
53
     *
54
     * @param \stdClass $template
55
     */
56
    public function __construct($template) {
57
        $this->id = $template->id;
58
        $this->name = $template->name;
59
        $this->contextid = $template->contextid;
60
    }
61
 
62
    /**
63
     * Handles saving data.
64
     *
65
     * @param \stdClass $data the template data
66
     */
67
    public function save($data) {
68
        global $DB;
69
 
70
        $savedata = new \stdClass();
71
        $savedata->id = $this->id;
72
        $savedata->name = $data->name;
73
        $savedata->timemodified = time();
74
 
75
        $DB->update_record('customcert_templates', $savedata);
76
 
77
        // Only trigger event if the name has changed.
78
        if ($this->get_name() != $data->name) {
79
            \mod_customcert\event\template_updated::create_from_template($this)->trigger();
80
        }
81
    }
82
 
83
    /**
84
     * Handles adding another page to the template.
85
     *
86
     * @param bool $triggertemplateupdatedevent
87
     * @return int the id of the page
88
     */
89
    public function add_page(bool $triggertemplateupdatedevent = true) {
90
        global $DB;
91
 
92
        // Set the page number to 1 to begin with.
93
        $sequence = 1;
94
        // Get the max page number.
95
        $sql = "SELECT MAX(sequence) as maxpage
96
                  FROM {customcert_pages} cp
97
                 WHERE cp.templateid = :templateid";
98
        if ($maxpage = $DB->get_record_sql($sql, ['templateid' => $this->id])) {
99
            $sequence = $maxpage->maxpage + 1;
100
        }
101
 
102
        // New page creation.
103
        $page = new \stdClass();
104
        $page->templateid = $this->id;
105
        $page->width = '210';
106
        $page->height = '297';
107
        $page->sequence = $sequence;
108
        $page->timecreated = time();
109
        $page->timemodified = $page->timecreated;
110
 
111
        // Insert the page.
112
        $pageid = $DB->insert_record('customcert_pages', $page);
113
 
114
        $page->id = $pageid;
115
 
116
        \mod_customcert\event\page_created::create_from_page($page, $this)->trigger();
117
 
118
        if ($triggertemplateupdatedevent) {
119
            \mod_customcert\event\template_updated::create_from_template($this)->trigger();
120
        }
121
 
122
        return $page->id;
123
    }
124
 
125
    /**
126
     * Handles saving page data.
127
     *
128
     * @param \stdClass $data the template data
129
     */
130
    public function save_page($data) {
131
        global $DB;
132
 
133
        // Set the time to a variable.
134
        $time = time();
135
 
136
        // Get the existing pages and save the page data.
137
        if ($pages = $DB->get_records('customcert_pages', ['templateid' => $data->tid])) {
138
            // Loop through existing pages.
139
            foreach ($pages as $page) {
140
                // Only update if there is a difference.
141
                if ($this->has_page_been_updated($page, $data)) {
142
                    $width = 'pagewidth_' . $page->id;
143
                    $height = 'pageheight_' . $page->id;
144
                    $leftmargin = 'pageleftmargin_' . $page->id;
145
                    $rightmargin = 'pagerightmargin_' . $page->id;
146
 
147
                    $p = new \stdClass();
148
                    $p->id = $page->id;
149
                    $p->width = $data->$width;
150
                    $p->height = $data->$height;
151
                    $p->leftmargin = $data->$leftmargin;
152
                    $p->rightmargin = $data->$rightmargin;
153
                    $p->timemodified = $time;
154
 
155
                    // Update the page.
156
                    $DB->update_record('customcert_pages', $p);
157
 
158
                    // Calling code is expected to trigger template_updated
159
                    // after this method.
160
                    \mod_customcert\event\page_updated::create_from_page($p, $this)->trigger();
161
                }
162
            }
163
        }
164
    }
165
 
166
    /**
167
     * Handles deleting the template.
168
     *
169
     * @return bool return true if the deletion was successful, false otherwise
170
     */
171
    public function delete() {
172
        global $DB;
173
 
174
        // Delete the pages.
175
        if ($pages = $DB->get_records('customcert_pages', ['templateid' => $this->id])) {
176
            foreach ($pages as $page) {
177
                $this->delete_page($page->id, false);
178
            }
179
        }
180
 
181
        // Now, finally delete the actual template.
182
        if (!$DB->delete_records('customcert_templates', ['id' => $this->id])) {
183
            return false;
184
        }
185
 
186
        \mod_customcert\event\template_deleted::create_from_template($this)->trigger();
187
 
188
        return true;
189
    }
190
 
191
    /**
192
     * Handles deleting a page from the template.
193
     *
194
     * @param int $pageid the template page
195
     * @param bool $triggertemplateupdatedevent False if page is being deleted
196
     * during deletion of template.
197
     */
198
    public function delete_page(int $pageid, bool $triggertemplateupdatedevent = true): void {
199
        global $DB;
200
 
201
        // Get the page.
202
        $page = $DB->get_record('customcert_pages', ['id' => $pageid], '*', MUST_EXIST);
203
 
204
        // The element may have some extra tasks it needs to complete to completely delete itself.
205
        if ($elements = $DB->get_records('customcert_elements', ['pageid' => $page->id])) {
206
            foreach ($elements as $element) {
207
                // Get an instance of the element class.
208
                if ($e = \mod_customcert\element_factory::get_element_instance($element)) {
209
                    $e->delete();
210
                } else {
211
                    // The plugin files are missing, so just remove the entry from the DB.
212
                    $DB->delete_records('customcert_elements', ['id' => $element->id]);
213
                }
214
            }
215
        }
216
 
217
        // Delete this page.
218
        $DB->delete_records('customcert_pages', ['id' => $page->id]);
219
 
220
        \mod_customcert\event\page_deleted::create_from_page($page, $this)->trigger();
221
 
222
        // Now we want to decrease the page number values of
223
        // the pages that are greater than the page we deleted.
224
        $sql = "UPDATE {customcert_pages}
225
                   SET sequence = sequence - 1
226
                 WHERE templateid = :templateid
227
                   AND sequence > :sequence";
228
        $DB->execute($sql, ['templateid' => $this->id, 'sequence' => $page->sequence]);
229
 
230
        if ($triggertemplateupdatedevent) {
231
            \mod_customcert\event\template_updated::create_from_template($this)->trigger();
232
        }
233
    }
234
 
235
    /**
236
     * Handles deleting an element from the template.
237
     *
238
     * @param int $elementid the template page
239
     */
240
    public function delete_element($elementid) {
241
        global $DB;
242
 
243
        // Ensure element exists and delete it.
244
        $element = $DB->get_record('customcert_elements', ['id' => $elementid], '*', MUST_EXIST);
245
 
246
        // Get an instance of the element class.
247
        if ($e = \mod_customcert\element_factory::get_element_instance($element)) {
248
            $e->delete();
249
        } else {
250
            // The plugin files are missing, so just remove the entry from the DB.
251
            $DB->delete_records('customcert_elements', ['id' => $elementid]);
252
        }
253
 
254
        // Now we want to decrease the sequence numbers of the elements
255
        // that are greater than the element we deleted.
256
        $sql = "UPDATE {customcert_elements}
257
                   SET sequence = sequence - 1
258
                 WHERE pageid = :pageid
259
                   AND sequence > :sequence";
260
        $DB->execute($sql, ['pageid' => $element->pageid, 'sequence' => $element->sequence]);
261
 
262
        \mod_customcert\event\template_updated::create_from_template($this)->trigger();
263
    }
264
 
265
    /**
266
     * Generate the PDF for the template.
267
     *
268
     * @param bool $preview true if it is a preview, false otherwise
269
     * @param int $userid the id of the user whose certificate we want to view
270
     * @param bool $return Do we want to return the contents of the PDF?
271
     * @return string|void Can return the PDF in string format if specified.
272
     */
273
    public function generate_pdf(bool $preview = false, int $userid = null, bool $return = false) {
274
        global $CFG, $DB, $USER;
275
 
276
        if (empty($userid)) {
277
            $user = $USER;
278
        } else {
279
            $user = \core_user::get_user($userid);
280
        }
281
 
282
        require_once($CFG->libdir . '/pdflib.php');
283
        require_once($CFG->dirroot . '/mod/customcert/lib.php');
284
 
285
        // Get the pages for the template, there should always be at least one page for each template.
286
        if ($pages = $DB->get_records('customcert_pages', ['templateid' => $this->id], 'sequence ASC')) {
287
            // Create the pdf object.
288
            $pdf = new \pdf();
289
 
290
            $customcert = $DB->get_record('customcert', ['templateid' => $this->id]);
291
 
292
            // I want to have my digital diplomas without having to change my preferred language.
293
            $userlang = $USER->lang ?? current_language();
294
 
295
            // Check the $customcert exists as it is false when previewing from mod/customcert/manage_templates.php.
296
            if ($customcert) {
297
                $forcelang = mod_customcert_force_current_language($customcert->language);
298
                if (!empty($forcelang)) {
299
                    // This is a failsafe -- if an exception triggers during the template rendering, this should still execute.
300
                    // Preventing a user from getting trapped with the wrong language.
301
                    \core_shutdown_manager::register_function('force_current_language', [$userlang]);
302
                }
303
            }
304
 
305
            // If the template belongs to a certificate then we need to check what permissions we set for it.
306
            if (!empty($customcert->protection)) {
307
                $protection = explode(', ', $customcert->protection);
308
                $pdf->SetProtection($protection);
309
            }
310
 
311
            if (empty($customcert->deliveryoption)) {
312
                $deliveryoption = certificate::DELIVERY_OPTION_INLINE;
313
            } else {
314
                $deliveryoption = $customcert->deliveryoption;
315
            }
316
 
317
            // Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
318
            $filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.');
319
 
320
            $pdf->setPrintHeader(false);
321
            $pdf->setPrintFooter(false);
322
            $pdf->SetTitle($filename);
323
            $pdf->SetAutoPageBreak(true, 0);
324
 
325
            // This is the logic the TCPDF library uses when processing the name. This makes names
326
            // such as 'الشهادة' become empty, so set a default name in these cases.
327
            $filename = preg_replace('/[\s]+/', '_', $filename);
328
            $filename = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $filename);
329
 
330
            if (empty($filename)) {
331
                $filename = get_string('certificate', 'customcert');
332
            }
333
 
334
            $filename = clean_filename($filename . '.pdf');
335
            // Loop through the pages and display their content.
336
            foreach ($pages as $page) {
337
                // Add the page to the PDF.
338
                if ($page->width > $page->height) {
339
                    $orientation = 'L';
340
                } else {
341
                    $orientation = 'P';
342
                }
343
                $pdf->AddPage($orientation, [$page->width, $page->height]);
344
                $pdf->SetMargins($page->leftmargin, 0, $page->rightmargin);
345
                // Get the elements for the page.
346
                if ($elements = $DB->get_records('customcert_elements', ['pageid' => $page->id], 'sequence ASC')) {
347
                    // Loop through and display.
348
                    foreach ($elements as $element) {
349
                        // Get an instance of the element class.
350
                        if ($e = \mod_customcert\element_factory::get_element_instance($element)) {
351
                            $e->render($pdf, $preview, $user);
352
                        }
353
                    }
354
                }
355
            }
356
 
357
            // Check the $customcert exists as it is false when previewing from mod/customcert/manage_templates.php.
358
            if ($customcert) {
359
                // We restore original language.
360
                if ($userlang != $customcert->language) {
361
                    mod_customcert_force_current_language($userlang);
362
                }
363
            }
364
 
365
            if ($return) {
366
                return $pdf->Output('', 'S');
367
            }
368
 
369
            $pdf->Output($filename, $deliveryoption);
370
        }
371
    }
372
 
373
    /**
374
     * Handles copying this template into another.
375
     *
376
     * @param object $copytotemplate The template instance to copy to
377
     */
378
    public function copy_to_template($copytotemplate) {
379
        global $DB;
380
 
381
        $copytotemplateid = $copytotemplate->get_id();
382
 
383
        // Get the pages for the template, there should always be at least one page for each template.
384
        if ($templatepages = $DB->get_records('customcert_pages', ['templateid' => $this->id])) {
385
            // Loop through the pages.
386
            foreach ($templatepages as $templatepage) {
387
                $page = clone($templatepage);
388
                $page->templateid = $copytotemplateid;
389
                $page->timecreated = time();
390
                $page->timemodified = $page->timecreated;
391
                // Insert into the database.
392
                $page->id = $DB->insert_record('customcert_pages', $page);
393
                \mod_customcert\event\page_created::create_from_page($page, $copytotemplate)->trigger();
394
                // Now go through the elements we want to load.
395
                if ($templateelements = $DB->get_records('customcert_elements', ['pageid' => $templatepage->id])) {
396
                    foreach ($templateelements as $templateelement) {
397
                        $element = clone($templateelement);
398
                        $element->pageid = $page->id;
399
                        $element->timecreated = time();
400
                        $element->timemodified = $element->timecreated;
401
                        // Ok, now we want to insert this into the database.
402
                        $element->id = $DB->insert_record('customcert_elements', $element);
403
                        // Load any other information the element may need to for the template.
404
                        if ($e = \mod_customcert\element_factory::get_element_instance($element)) {
405
                            if (!$e->copy_element($templateelement)) {
406
                                // Failed to copy - delete the element.
407
                                $e->delete();
408
                            } else {
409
                                \mod_customcert\event\element_created::create_from_element($e)->trigger();
410
                            }
411
                        }
412
                    }
413
                }
414
            }
415
 
416
            // Trigger event if loading a template in a course module instance.
417
            // (No event triggered if copying a system-wide template as
418
            // create() triggers this).
419
            if ($copytotemplate->get_context() != \context_system::instance()) {
420
                \mod_customcert\event\template_updated::create_from_template($copytotemplate)->trigger();
421
            }
422
        }
423
    }
424
 
425
    /**
426
     * Handles moving an item on a template.
427
     *
428
     * @param string $itemname the item we are moving
429
     * @param int $itemid the id of the item
430
     * @param string $direction the direction
431
     */
432
    public function move_item($itemname, $itemid, $direction) {
433
        global $DB;
434
 
435
        $table = 'customcert_';
436
        if ($itemname == 'page') {
437
            $table .= 'pages';
438
        } else { // Must be an element.
439
            $table .= 'elements';
440
        }
441
 
442
        if ($moveitem = $DB->get_record($table, ['id' => $itemid])) {
443
            // Check which direction we are going.
444
            if ($direction == 'up') {
445
                $sequence = $moveitem->sequence - 1;
446
            } else { // Must be down.
447
                $sequence = $moveitem->sequence + 1;
448
            }
449
 
450
            // Get the item we will be swapping with. Make sure it is related to the same template (if it's
451
            // a page) or the same page (if it's an element).
452
            if ($itemname == 'page') {
453
                $params = ['templateid' => $moveitem->templateid];
454
            } else { // Must be an element.
455
                $params = ['pageid' => $moveitem->pageid];
456
            }
457
            $swapitem = $DB->get_record($table, $params + ['sequence' => $sequence]);
458
        }
459
 
460
        // Check that there is an item to move, and an item to swap it with.
461
        if ($moveitem && !empty($swapitem)) {
462
            $DB->set_field($table, 'sequence', $swapitem->sequence, ['id' => $moveitem->id]);
463
            $DB->set_field($table, 'sequence', $moveitem->sequence, ['id' => $swapitem->id]);
464
 
465
            \mod_customcert\event\template_updated::create_from_template($this)->trigger();
466
        }
467
    }
468
 
469
    /**
470
     * Returns the id of the template.
471
     *
472
     * @return int the id of the template
473
     */
474
    public function get_id() {
475
        return $this->id;
476
    }
477
 
478
    /**
479
     * Returns the name of the template.
480
     *
481
     * @return string the name of the template
482
     */
483
    public function get_name() {
484
        return $this->name;
485
    }
486
 
487
    /**
488
     * Returns the context id.
489
     *
490
     * @return int the context id
491
     */
492
    public function get_contextid() {
493
        return $this->contextid;
494
    }
495
 
496
    /**
497
     * Returns the context id.
498
     *
499
     * @return \context the context
500
     */
501
    public function get_context() {
502
        return \context::instance_by_id($this->contextid);
503
    }
504
 
505
    /**
506
     * Returns the context id.
507
     *
508
     * @return \context_module|null the context module, null if there is none
509
     */
510
    public function get_cm() {
511
        $context = $this->get_context();
512
        if ($context->contextlevel === CONTEXT_MODULE) {
513
            return get_coursemodule_from_id('customcert', $context->instanceid, 0, false, MUST_EXIST);
514
        }
515
 
516
        return null;
517
    }
518
 
519
    /**
520
     * Ensures the user has the proper capabilities to manage this template.
521
     *
522
     * @throws \required_capability_exception if the user does not have the necessary capabilities (ie. Fred)
523
     */
524
    public function require_manage() {
525
        require_capability('mod/customcert:manage', $this->get_context());
526
    }
527
 
528
    /**
529
     * Creates a template.
530
     *
531
     * @param string $templatename the name of the template
532
     * @param int $contextid the context id
533
     * @return \mod_customcert\template the template object
534
     */
535
    public static function create($templatename, $contextid) {
536
        global $DB;
537
 
538
        $template = new \stdClass();
539
        $template->name = $templatename;
540
        $template->contextid = $contextid;
541
        $template->timecreated = time();
542
        $template->timemodified = $template->timecreated;
543
        $template->id = $DB->insert_record('customcert_templates', $template);
544
 
545
        $template = new \mod_customcert\template($template);
546
 
547
        \mod_customcert\event\template_created::create_from_template($template)->trigger();
548
 
549
        return $template;
550
    }
551
 
552
    /**
553
     * Checks if a page has been updated given form information
554
     *
555
     * @param \stdClass $page
556
     * @param \stdClass $formdata
557
     * @return bool
558
     */
559
    private function has_page_been_updated($page, $formdata): bool {
560
        $width = 'pagewidth_' . $page->id;
561
        $height = 'pageheight_' . $page->id;
562
        $leftmargin = 'pageleftmargin_' . $page->id;
563
        $rightmargin = 'pagerightmargin_' . $page->id;
564
 
565
        if ($page->width != $formdata->$width) {
566
            return true;
567
        }
568
 
569
        if ($page->height != $formdata->$height) {
570
            return true;
571
        }
572
 
573
        if ($page->leftmargin != $formdata->$leftmargin) {
574
            return true;
575
        }
576
 
577
        if ($page->rightmargin != $formdata->$rightmargin) {
578
            return true;
579
        }
580
 
581
        return false;
582
    }
583
}