config = $config; $this->mpdf = $mpdf; } public function getTemplatePath(): ?string { if (!isset($this->templatePath)) { $template_path = $this->config->get('export.template_path', FALSE); if (!$template_path) { $template_path = readline('Enter template file path: '); } if (!file_exists($template_path)) { throw new Exception('Template file not found!'); } $this->templatePath = $template_path; } return $this->templatePath; } public function setTemplatePath(string $path): void { if (file_exists($path)) { $this->templatePath = $path; return; } throw new Exception('Invoice template file not found!'); } // @TODO move this method to CsvReport. // Add classes to table elements. // @TODO would it make sense to allow more per user extending? // @TODO - too much assumptions on data structure. Create a class with // precise data structure and use that to pass the data around. public function parsedDataToHtmlTable(array $data): ?string { $table = ''; $header = array_shift($data); $classes = ''; foreach ($header as $index => $cell) { $table .= ""; } $table .= ''; foreach ($data as $row_index => $row) { if (!$row) { if ($row === ReportCsvInterface::SEPARATOR_MEDIUM) { $classes = 'bold'; } elseif ($row === ReportCsvInterface::SEPARATOR_HARD) { $classes = 'bold center'; } continue; } list($cells, $colspan) = [[], 0]; foreach ($row as $index => $cell) { if (!$cell) { $colspan += 1; continue; } if ($colspan) { $colspan += 1; $cells[] = ""; $colspan = 0; } else { $cells[] = ""; } } $rows[] = "" . implode($cells) . ''; $classes = ''; } $table .= implode('', $rows); $table .= '
{$cell}
{$cell}{$cell}
'; var_dump($table); return $table; } public function replaceTokensInTemplate(string $template_path, array $tokens): ?string { $template = file_get_contents($template_path); foreach ($tokens as $key => $value) { $template = str_replace("[[{$key}]]", $value, $template); } return $template; } // @TODO write a method to gather tokens. public function getTokensInTemplate(string $template): array { // @TODO find substrings of type [[key]] preg_match_all('/\[\[([a-z0-9-_]+)\]\]/', $template, $match); return $match[1]; } // @TODO support multiple templates by adding template id in config. /** * Get tokens to replace in the template. * * @param string $template_path * Path to the template file (long term plan is to support multiple templates). * @param bool $skip_missing * Just skip missing tokens. * @param array $runtime_tokens * Provide tokens at runtime of the application (not supported yet). @TODO * @param string $config * Config path to tokens. * * @return array * Token keys and values array. */ public function gatherTokensForTemplate(string $template_path, bool $skip_missing = FALSE, array $runtime_tokens = [], string $config = 'export.tokens'): array { list($tokens, $missing) = [[], []]; $token_keys = $this->getTokensInTemplate(file_get_contents($template_path)); $config_tokens = $this->config->get($config); foreach ($token_keys as $token_key) { if (isset($runtime_tokens[$token_key])) { $tokens[$token_key] = $runtime_tokens[$token_key]; } elseif (!isset($config_tokens[$token_key]) && !$skip_missing) { $tokens[$token_key] = readline("Enter value to replace [[{$token_key}]] in template: "); } elseif (isset($config_tokens[$token_key])) { $tokens[$token_key] = $config_tokens[$token_key]; } else { $missing[] = $token_key; } } return $tokens; } public function pdfExport(string $html, $output = null): bool { $this->mpdf->SetProtection(array('print')); // @TODO make configurable. $this->mpdf->SetTitle("Invoice"); $this->mpdf->SetAuthor("rprt-cli"); $this->mpdf->SetDisplayMode('fullpage'); $this->mpdf->WriteHTML($html); $this->mpdf->Output($this->getOutput(), Destination::FILE); return file_exists($this->output); } protected function getOutput() { if (isset($this->output)) { return $this->output; } $output = $this->config->get('export.output', NULL) ?? readline('Enter output file path: '); $date = strtotime("-1 month"); $output = str_replace('[[month]]', date('F', $date), $output); $output = str_replace('[[year]]', date('Y', $date), $output); $this->output = $output; return $output; } public function setOutput(string $path): void { $this->output = $path; } public function fromDefaultDataToPdf(array $data, array $tokens = []): string { $template_path = $this->getTemplatePath(); $tokens = $this->defaultTokens(); $tokens['table'] = $this->parsedDataToHtmlTable($data); $tokens = $this->gatherTokensForTemplate($template_path, FALSE, $tokens); $html = $this->replaceTokensInTemplate($template_path, $tokens); $success = $this->pdfExport($html); if ($success) { return $this->getOutput(); } return ''; } /** * Get default tokens. */ protected function defaultTokens(): array { $tokens = []; $tokens['today'] = date('j. m. y'); $month_ago = strtotime('1 month ago'); $tokens['number'] = date('m/y', $month_ago); $tokens['date_start'] = date('1. m. Y', $month_ago); $tokens['date_end'] = date("d. m. Y", mktime(0, 0, 0, (int) date("m"), 0)); return $tokens; } }