Compare commits

1 Commits
main ... report

Author SHA1 Message Date
pandeptwidyaop
f03abc8ac8 dev 2024-08-19 18:16:03 +08:00
35 changed files with 5281 additions and 39 deletions

View File

@@ -26,19 +26,3 @@ jobs:
docker push $REGISTRY
docker push $REGISTRY:$IMAGE_TAG
docker rmi $(docker images -q $REGISTRY:$IMAGE_TAG) -f
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Pull & Restart
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_VM_DEPLOYMENT_HOST }}
key: ${{ secrets.SSH_VM_DEPLOYMENT }}
username: ${{ secrets.SSH_VM_DEPLOYMENT_USERNAME }}
port: ${{ secrets.SSH_VM_DEPLOYMENT_PORT }}
script: |
cd ~/deployment/genpdf
docker compose pull
docker compose down -v
docker compose up -d

View File

@@ -30,6 +30,7 @@ RUN apt-get update && apt-get install -y \
RUN mkdir -p /usr/share/fonts/truetype/custom
COPY ./fonts/gilroy/* /usr/share/fonts/truetype/custom
COPY ./fonts/lexend/* /usr/share/fonts/truetype/custom
COPY ./fonts/visby/* /usr/share/fonts/truetype/custom
RUN fc-cache -f -v
# Download and install Composer

25
base.Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
FROM php:8.2-cli
# Install dependencies needed for Composer and PHP zip extension
RUN echo "deb http://deb.debian.org/debian bookworm contrib non-free" > /etc/apt/sources.list.d/contrib.list
RUN apt-get update && apt-get install -y \
curl \
unzip \
libzip-dev \
libreoffice \
fontconfig \
gcc \
g++ \
build-essential \
ttf-mscorefonts-installer \
&& docker-php-ext-install zip \
&& rm -rf /var/lib/apt/lists/*
# Install fonts
RUN mkdir -p /usr/share/fonts/truetype/custom
COPY ./fonts/gilroy/* /usr/share/fonts/truetype/custom
COPY ./fonts/lexend/* /usr/share/fonts/truetype/custom
RUN fc-cache -f -v
# Download and install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

View File

@@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y \
RUN mkdir -p /usr/share/fonts/truetype/custom
COPY ./fonts/gilroy/* /usr/share/fonts/truetype/custom
COPY ./fonts/lexend/* /usr/share/fonts/truetype/custom
COPY ./fonts/visby/* /usr/share/fonts/truetype/custom
RUN fc-cache -f -v
# Download and install Composer

View File

@@ -1 +0,0 @@
,pande,pandewidya.local,15.08.2024 07:34,file:///Users/pande/Library/Application%20Support/LibreOffice/4;

BIN
examples/Cover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
examples/Raport.docx Normal file

Binary file not shown.

5058
examples/pembahasan.json Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/.DS_Store vendored

Binary file not shown.

View File

@@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class Generate extends Command
class GenerateEbook extends Command
{
protected static $defaultName = "generate:ebook";

View File

@@ -0,0 +1,55 @@
<?php
namespace MenulisAi\Pdfgen\Command;
use MenulisAi\Pdfgen\Document\Ebook;
use MenulisAi\Pdfgen\Document\Table;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class GenerateTest extends Command
{
protected static $defaultName = "generate:test";
protected function configure()
{
$this->setDescription('Generate a PDF document file from JSON data')
->addArgument("input", InputArgument::REQUIRED, "Input path file JSON")
->addArgument("output", InputArgument::OPTIONAL, "Set the output path");
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$inPath = $input->getArgument("input");
$doc = new Table($inPath);
$path = $doc->compile();
$output->writeln($path);
$cmd = new Process([
"soffice",
"--headless",
"--convert-to",
"pdf",
"--outdir",
"/app/storage/",
$path
]);
$cmd->run();
if (!$cmd->isSuccessful()) {
throw new ProcessFailedException($cmd);
}
$output->writeln(rootPath("storage/" . pathinfo($path, PATHINFO_FILENAME) . ".pdf"));
return Command::SUCCESS;
}
}

View File

@@ -2,4 +2,25 @@
namespace MenulisAi\Pdfgen\Document;
interface Document {}
use Exception;
class Document
{
protected $object;
protected function openFile(string $path)
{
$file = file_get_contents($path);
if ($file === false) {
throw new Exception("Unable to read or open the file", 1);
}
$data = json_decode($file);
if (json_last_error() !== JSON_ERROR_NONE) {
// Handle error if the JSON could not be parsed
throw new Exception("Error read the json file: " . json_last_error_msg(), 1);
}
$this->object = $data;
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace MenulisAi\Pdfgen\Document;
interface Documentable
{
public function templateSource(): string;
public function compile(): string;
}

View File

@@ -5,10 +5,8 @@ namespace MenulisAi\Pdfgen\Document;
use PhpOffice\PhpWord\TemplateProcessor;
use Exception;
class Ebook implements Document
class Ebook extends Document implements Documentable
{
protected $object;
public function __construct(string $jsonPath)
{
$this->openFile($jsonPath);
@@ -114,21 +112,7 @@ class Ebook implements Document
return $proc->save();
}
protected function openFile(string $path)
{
$file = file_get_contents($path);
if ($file === false) {
throw new Exception("Unable to read or open the file", 1);
}
$data = json_decode($file);
if (json_last_error() !== JSON_ERROR_NONE) {
// Handle error if the JSON could not be parsed
throw new Exception("Error read the json file: " . json_last_error_msg(), 1);
}
$this->object = $data;
}
protected function intToAlphabet(int $number): string
{

103
src/Document/Table.php Normal file
View File

@@ -0,0 +1,103 @@
<?php
namespace MenulisAi\Pdfgen\Document;
use PhpOffice\PhpWord\Element\Table as ElementTable;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\SimpleType\Border;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\JcTable;
use PhpOffice\PhpWord\TemplateProcessor;
use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\SimpleType\TextAlignment;
use PhpOffice\PhpWord\Style\Table as StyleTable;
const PER_INCH = 1440;
class Table extends Document implements Documentable
{
public function __construct(string $jsonPath)
{
// $this->openFile($jsonPath);
}
public function templateSource(): string
{
return appPath("Template/Doc1.docx");
}
public function compile(): string
{
/**
* 1 Inch = 1440 point for TWIP / dxa
* A4 Paper (W x H) = 8.27 x 11.69 = 11908.9 x 16833.6
* Margin Left = 0.44" = 633.6
* Margin Right = 0.44" = 633.6
* Margin Top = 0.79" = 1137.6
* Margin Bottom = 0.79" = 1137.6
*/
$proc = new TemplateProcessor($this->templateSource());
$proc->setValue("name", "Pande Ganteng");
$proc->setValue("full_name", "Pande Ganteng");
$proc->setValue("email", "Pande@gmail.com");
$tableWidth = (8.27 * PER_INCH) - ((0.44 * 2) * PER_INCH);
$col1Width = $tableWidth * 0.4;
$col2Width = $tableWidth * 0.15;
$col3Width = $tableWidth * 0.15;
$col4Width = $tableWidth * 0.15;
$col5Width = $tableWidth * 0.15;
$table = new ElementTable([
'alignment' => JcTable::CENTER,
'borderColor' => '#072442',
'borderSize' => 10,
'width' => $tableWidth,
'unit' => TblWidth::TWIP,
'layout' => StyleTable::LAYOUT_AUTO,
'cellMarginTop' => 100,
'cellMarginLeft' => 100,
'cellMarginBottom' => 0,
'cellMarginRight' => 100,
]);
$table->addRow(800);
$table->addCell($col1Width, ['valign' => 'center', 'bgColor' => '#4169E1'])->addText('Kategori', ['bold' => true, 'name' => 'Visby Round CF', 'size' => 10, 'color' => '#ffffff'], ['alignment' => Jc::CENTER]);
$table->addCell($col2Width, ['valign' => 'center', 'bgColor' => '#4169E1'])->addText('Jawaban Benar', ['bold' => true, 'name' => 'Visby Round CF', 'size' => 10, 'color' => '#ffffff'], ['alignment' => Jc::CENTER]);
$table->addCell($col3Width, ['valign' => 'center', 'bgColor' => '#4169E1'])->addText('Jawaban Salah', ['bold' => true, 'name' => 'Visby Round CF', 'size' => 10, 'color' => '#ffffff'], ['alignment' => Jc::CENTER]);
$table->addCell($col4Width, ['valign' => 'center', 'bgColor' => '#4169E1'])->addText('Tidak Menjawab', ['bold' => true, 'name' => 'Visby Round CF', 'size' => 10, 'color' => '#ffffff'], ['alignment' => Jc::CENTER]);
$table->addCell($col5Width, ['valign' => 'center', 'bgColor' => '#4169E1'])->addText('% Jawaban Benar', ['bold' => true, 'name' => 'Visby Round CF', 'size' => 10, 'color' => '#ffffff'], ['alignment' => Jc::CENTER]);
// TWK
$table->addRow();
$table->addCell($col1Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderBottomSize' => 0, 'borderBottomStyle' => Border::NONE])->addText("Tes Wawasan Kebangsaan", ['bold' => true, 'name' => 'Visby Round CF', 'size' => 9, 'color' => '#072442']);
$table->addCell($col2Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderBottomSize' => 0, 'borderBottomStyle' => Border::NONE])->addText("17", ['bold' => true, 'name' => 'Visby Round CF', 'size' => 9, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col3Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderBottomSize' => 0, 'borderBottomStyle' => Border::NONE])->addText("13", ['bold' => true, 'name' => 'Visby Round CF', 'size' => 9, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col4Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderBottomSize' => 0, 'borderBottomStyle' => Border::NONE])->addText("0", ['bold' => true, 'name' => 'Visby Round CF', 'size' => 9, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col5Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderBottomSize' => 0, 'borderBottomStyle' => Border::NONE])->addText("56%", ['bold' => true, 'name' => 'Visby Round CF', 'size' => 9, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$dataTwk = ['Nasionalisme', 'Integritas', 'Bela Negara', 'Pilar Negara', 'Bahasa Indonesia', 'Bahasa Bali'];
foreach ($dataTwk as $key => $dt) {
$isLast = false;
if (count($dataTwk) == $key + 1) {
$isLast = true;
}
$table->addRow();
$table->addCell($col1Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderTopSize' => 0, 'borderBottomSize' => $isLast ? 10 : 0, 'borderTopStyle' => Border::NONE, 'borderBottomStyle' => $isLast ? Border::SINGLE : Border::NONE])->addText(" " . mb_chr(8226, 'UTF-8') . " " . $dt, ['bold' => false, 'name' => 'Visby Round CF', 'size' => 8, 'color' => '#072442']);
$table->addCell($col2Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderTopSize' => 0, 'borderBottomSize' => $isLast ? 10 : 0, 'borderTopStyle' => Border::NONE, 'borderBottomStyle' => $isLast ? Border::SINGLE : Border::NONE])->addText("17", ['bold' => false, 'name' => 'Visby Round CF', 'size' => 8, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col3Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderTopSize' => 0, 'borderBottomSize' => $isLast ? 10 : 0, 'borderTopStyle' => Border::NONE, 'borderBottomStyle' => $isLast ? Border::SINGLE : Border::NONE])->addText("13", ['bold' => false, 'name' => 'Visby Round CF', 'size' => 8, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col4Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderTopSize' => 0, 'borderBottomSize' => $isLast ? 10 : 0, 'borderTopStyle' => Border::NONE, 'borderBottomStyle' => $isLast ? Border::SINGLE : Border::NONE])->addText("0", ['bold' => false, 'name' => 'Visby Round CF', 'size' => 8, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
$table->addCell($col5Width, ['valign' => 'center', 'bgColor' => '#f0f3fd', 'borderTopSize' => 0, 'borderBottomSize' => $isLast ? 10 : 0, 'borderTopStyle' => Border::NONE, 'borderBottomStyle' => $isLast ? Border::SINGLE : Border::NONE])->addText("56%", ['bold' => false, 'name' => 'Visby Round CF', 'size' => 8, 'color' => '#072442'], ['alignment' => Jc::CENTER]);
}
$dataTkp = ['Verbal Analogi'];
$proc->setComplexValue('table', $table);
$proc->saveAs(rootPath("examples/Raport.docx"));
return rootPath("examples/Raport.docx");
}
}

View File

@@ -2,7 +2,8 @@
namespace MenulisAi\Pdfgen;
use MenulisAi\Pdfgen\Command\Generate;
use MenulisAi\Pdfgen\Command\GenerateEbook;
use MenulisAi\Pdfgen\Command\GenerateTest;
use Symfony\Component\Console\Command\Command;
class Register
@@ -13,7 +14,8 @@ class Register
public function init(): array
{
return [
new Generate("generate:ebook")
new GenerateEbook("generate:ebook"),
new GenerateTest("generate:test")
];
}
}

BIN
src/Template/Doc1.docx Normal file

Binary file not shown.

BIN
src/Template/Raport.docx Normal file

Binary file not shown.

BIN
src/Template/Raport.odt Normal file

Binary file not shown.