diff --git a/certificates.php b/certificates.php index 7ccddbfa..3ab2b0ad 100644 --- a/certificates.php +++ b/certificates.php @@ -63,6 +63,14 @@ $outputpage = new \tool_certificate\output\issues_page($template->get_id()); $data = $outputpage->export_for_template($PAGE->get_renderer('core')); + +$downloadform = new \tool_certificate\download_issues_form($template->get_id()); +if ($downloadissues = $downloadform->get_data()) { + $outputpage->output_issues_pdf($template, $downloadissues); + die(); +} +$data['content'] .= $downloadform->render(); + $data += ['heading' => get_string('issuedcertificates', 'tool_certificate')]; if ($template->can_issue_to_anybody()) { $data += ['addbutton' => true, 'addbuttontitle' => get_string('issuecertificates', 'tool_certificate'), diff --git a/classes/download_issues_form.php b/classes/download_issues_form.php new file mode 100644 index 00000000..37814a99 --- /dev/null +++ b/classes/download_issues_form.php @@ -0,0 +1,56 @@ +templateid = $templateid; + } + + public function render(): string { + return << +
+ + + + + +
+ +HTML; + } + + public function get_data() { + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + return false; + } + + $downloadissues = required_param('downloadissues', PARAM_ALPHA); + return $downloadissues; + } + + protected function definition(): void { + $this->_form->setAttributes(['class' => 'form-inline']); + + $templateid = $this->_customdata['templateid']; + $this->_form->addElement('hidden', 'templateid', $templateid); + $this->_form->setType('id', PARAM_INT); + + $options = + [ + 'pdf' => 'Merged PDF', + 'pdfdecollate' => 'Merged PDF (De-collated)', + ]; + $this->_form->addElement('select', 'downloadissues', 'Download issued PDFs as', $options); + $this->_form->setType('downloadissues', PARAM_TEXT); + + $submit = $this->_form->addElement('submit', 'submit', 'Download PDFs'); + $submit->setAttributes(['class' => 'btn btn-secondary']); + } +} \ No newline at end of file diff --git a/classes/output/issues_page.php b/classes/output/issues_page.php index bbd5d147..3169bb2c 100644 --- a/classes/output/issues_page.php +++ b/classes/output/issues_page.php @@ -33,6 +33,11 @@ class issues_page implements \templatable, \renderable { /** @var int */ protected $templateid; + /** + * @var \stdClass[] The rows that were displayed in the table + */ + public array $rows; + /** * templates_page constructor. * @@ -53,6 +58,112 @@ public function export_for_template(renderer_base $output): array { $report = system_report_factory::create(issues::class, $context, '', '', 0, ['templateid' => $this->templateid]); - return ['content' => $report->output()]; + $result = ['content' => $report->output()]; + if (isset($report->rows)) { + $this->rows = $report->rows; + } + else + { + $this->rows = []; + } + return $result; + } + + /** + * @throws \InvalidArgumentException + * @throws \setasign\Fpdi\PdfParser\PdfParserException + * @throws \setasign\Fpdi\PdfParser\PdfParserException + */ + public function output_issues_pdf(template $template, string $type): void { + global $CFG; + $files = []; + $handles = []; + foreach ($this->rows as $row) { + $file = $template->get_issue_file($row); + $files[] = $file; + $handles[$file->get_id()] = $file->get_content_file_handle(); + } + + $debug = optional_param('debug', false, PARAM_BOOL); + + require_once($CFG->libdir . '/pdflib.php'); + require_once($CFG->dirroot . '/mod/assign/feedback/editpdf/fpdi/autoload.php'); + + // end all output buffers if any + while (ob_get_level()) + { + ob_get_clean(); + } + + try { + $pdf = new \setasign\Fpdi\Tcpdf\Fpdi(); + $count = count($files); + $name = clean_filename($template->get_name()); + $at = date('Y-m-d H-i-s'); + $name = "$name - $count certificate(s) - $at"; + + if ($type == 'pdf') { + $position = 0; + foreach ($files as $file) { + $position++; + $filePages = $pdf->setSourceFile($handles[$file->get_id()]); + for ($pageNumber = 1; $pageNumber <= $filePages; $pageNumber++) { + $sourcePage = $pdf->importPage($pageNumber); + $size = $pdf->getTemplateSize($sourcePage); + $pdf->AddPage($size['orientation'], array($size['width'], $size['height'])); + + $pdf->useTemplate($sourcePage); + + if ($debug) { + $pdf->SetFont('Helvetica'); + $pdf->SetTextColor(200, 0, 0); + $pdf->SetXY(5, 5); + $pdf->Write(2, "PDF $position/$count, Page $pageNumber/$filePages"); + } + } + } + + $pdf->Output("$name.pdf"); + } + else if ($type == 'pdfdecollate') { + $pageCount = 1; + for ($pageNumber = 1; $pageNumber <= $pageCount; $pageNumber++) { + $position = 0; + foreach ($files as $file) { + $position++; + $filePages = $pdf->setSourceFile($handles[$file->get_id()]); + if ($pageNumber > $filePages) { + continue; + } + if ($filePages > $pageCount) { + $pageCount = $filePages; + } + + $sourcePage = $pdf->importPage($pageNumber); + $size = $pdf->getTemplateSize($sourcePage); + $pdf->AddPage($size['orientation'], array($size['width'], $size['height'])); + + $pdf->useTemplate($sourcePage); + + if ($debug) { + $pdf->SetFont('Helvetica'); + $pdf->SetTextColor(200, 0, 0); + $pdf->SetXY(5, 5); + $pdf->Write(2, "PDF $position/$count, Page $pageNumber/$filePages"); + } + } + } + + $pdf->Output("$name - ordered.pdf"); + } + else { + throw new \InvalidArgumentException("Unknown download type: $type"); + } + } + finally { + foreach ($handles as $handle) { + fclose($handle); + } + } } } diff --git a/classes/reportbuilder/local/systemreports/issues.php b/classes/reportbuilder/local/systemreports/issues.php index 9ca11a7a..8fac8620 100644 --- a/classes/reportbuilder/local/systemreports/issues.php +++ b/classes/reportbuilder/local/systemreports/issues.php @@ -245,8 +245,18 @@ protected function add_actions(): void { */ public function row_callback(stdClass $row): void { $this->userid = (int) $row->userid; + + if (!isset($this->rows)) { + $this->rows = []; + } + $this->rows[] = $row; } + /** + * @var stdClass[] + */ + public array $rows; + /** * Callback for the fullname to display badge for archived issues. *