This commit is contained in:
Adrian Hopek 2022-05-10 14:54:09 +02:00
parent 22c5f7bb54
commit 37d9404226
6 changed files with 328 additions and 2 deletions

View File

@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
namespace Toby\Domain;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use PhpOffice\PhpWord\TemplateProcessor;
use Toby\Eloquent\Models\Resume;
class ResumeGenerator
{
public function generate(Resume $resume): string
{
$uid = Str::uuid();
$path = storage_path("${uid}.docx");
$processor = new TemplateProcessor($this->getTemplate());
$processor->setValue("id", $resume->id);
$processor->setValue("name", $resume->user ? $resume->user->profile->full_name : $resume->name);
$this->fillTechnologies($processor, $resume);
$this->fillLanguages($processor, $resume);
$this->fillEducation($processor, $resume);
$this->fillProjects($processor, $resume);
$processor->saveAs($path);
return $path;
}
public function getTemplate(): string
{
return resource_path("views/docx/resume_eng.docx");
}
protected function fillTechnologies(TemplateProcessor $processor, Resume $resume): void
{
if ($resume->technologies->count() <= 0) {
$processor->deleteBlock("technologies");
return;
}
$processor->cloneBlock("technologies", 0, true, false, $this->getTechnologies($resume));
}
protected function fillLanguages(TemplateProcessor $processor, Resume $resume): void
{
if ($resume->education->count() <= 0) {
$processor->deleteBlock("languages");
return;
}
$processor->cloneBlock("languages", 0, true, false, $this->getLanguages($resume));
}
protected function fillEducation(TemplateProcessor $processor, Resume $resume): void
{
if ($resume->education->count() <= 0) {
$processor->deleteBlock("education");
return;
}
$processor->cloneBlock("education", 0, true, false, $this->getEducation($resume));
}
protected function fillProjects(TemplateProcessor $processor, Resume $resume): void
{
if ($resume->projects->count() <= 0) {
$processor->deleteBlock("projects");
return;
}
$processor->cloneBlock("projects", $resume->projects->count(), true, true);
foreach ($resume->projects as $index => $project) {
$index += 1;
$processor->setValues($this->getProject($project, $index));
$processor->cloneBlock("project_technologies#{$index}", 0, true, false, $this->getProjectTechnologies($project, $index));
}
}
protected function getProject(array $project, int $index): array
{
return [
"index#{$index}" => $index,
"start_date#{$index}" => Carbon::create($project["startDate"])->toDisplayString(),
"end_date#{$index}" => Carbon::create($project["endDate"])->toDisplayString(),
"description#{$index}" => $project["description"],
"tasks#{$index}" => $project["tasks"],
];
}
protected function getProjectTechnologies(array $project, int $index): array
{
$technologies = new Collection($project["technologies"] ?? []);
return $technologies->map(fn(string $name) => [
"technology#{$index}" => $name,
])->all();
}
protected function getTechnologies(Resume $resume): array
{
return $resume->technologies->map(fn(array $technology): array => [
"technology_name" => $technology["name"],
"technology_level" => $technology["level"],
])->all();
}
protected function getLanguages(Resume $resume): array
{
return $resume->languages->map(fn(array $language): array => [
"language_name" => $language["name"],
"language_level" => $language["level"],
])->all();
}
protected function getEducation(Resume $resume): array
{
return $resume->education->map(fn(array $project, int $index): array => [
"start_date" => Carbon::create($project["startDate"])->toDisplayString(),
"end_date" => Carbon::create($project["endDate"])->toDisplayString(),
"school" => $project["school"],
"field_of_study" => $project["fieldOfStudy"],
"degree" => $project["degree"],
])->all();
}
}

View File

@ -6,6 +6,8 @@ namespace Toby\Infrastructure\Http\Controllers;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Inertia\Response; use Inertia\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse as BinaryFileResponseAlias;
use Toby\Domain\ResumeGenerator;
use Toby\Eloquent\Models\Resume; use Toby\Eloquent\Models\Resume;
use Toby\Eloquent\Models\Technology; use Toby\Eloquent\Models\Technology;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
@ -39,6 +41,15 @@ class ResumeController extends Controller
]); ]);
} }
public function show(Resume $resume, ResumeGenerator $generator): BinaryFileResponseAlias
{
$path = $generator->generate($resume);
return response()
->download($path, "resume-{$resume->id}.docx")
->deleteFileAfterSend();
}
public function store(ResumeRequest $request): RedirectResponse public function store(ResumeRequest $request): RedirectResponse
{ {
$resume = new Resume(); $resume = new Resume();

View File

@ -19,6 +19,7 @@
"laravel/telescope": "^4.6", "laravel/telescope": "^4.6",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"maatwebsite/excel": "^3.1", "maatwebsite/excel": "^3.1",
"phpoffice/phpword": "^0.18.3",
"rackbeat/laravel-ui-avatars": "^1.0", "rackbeat/laravel-ui-avatars": "^1.0",
"spatie/laravel-google-calendar": "^3.5", "spatie/laravel-google-calendar": "^3.5",
"spatie/laravel-model-states": "^2.1" "spatie/laravel-model-states": "^2.1"

176
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "414a1fc13e0731e59605248bd4e39de6", "content-hash": "3e4ab38084e10e25b26a11dc275dd007",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
@ -1731,6 +1731,68 @@
], ],
"time": "2021-12-16T16:49:26+00:00" "time": "2021-12-16T16:49:26+00:00"
}, },
{
"name": "laminas/laminas-escaper",
"version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-escaper.git",
"reference": "58af67282db37d24e584a837a94ee55b9c7552be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be",
"reference": "58af67282db37d24e584a837a94ee55b9c7552be",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-mbstring": "*",
"php": "^7.4 || ~8.0.0 || ~8.1.0"
},
"conflict": {
"zendframework/zend-escaper": "*"
},
"require-dev": {
"infection/infection": "^0.26.6",
"laminas/laminas-coding-standard": "~2.3.0",
"maglnet/composer-require-checker": "^3.8.0",
"phpunit/phpunit": "^9.5.18",
"psalm/plugin-phpunit": "^0.16.1",
"vimeo/psalm": "^4.22.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Laminas\\Escaper\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
"homepage": "https://laminas.dev",
"keywords": [
"escaper",
"laminas"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-escaper/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-escaper/issues",
"rss": "https://github.com/laminas/laminas-escaper/releases.atom",
"source": "https://github.com/laminas/laminas-escaper"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2022-03-08T20:15:36+00:00"
},
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v9.7.0", "version": "v9.7.0",
@ -3958,6 +4020,118 @@
}, },
"time": "2022-02-18T12:57:07+00:00" "time": "2022-02-18T12:57:07+00:00"
}, },
{
"name": "phpoffice/phpword",
"version": "0.18.3",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PHPWord.git",
"reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/be0190cd5d8f95b4be08d5853b107aa4e352759a",
"reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a",
"shasum": ""
},
"require": {
"ext-xml": "*",
"laminas/laminas-escaper": "^2.2",
"php": "^5.3.3 || ^7.0 || ^8.0"
},
"require-dev": {
"dompdf/dompdf": "0.8.* || 1.0.*",
"ext-gd": "*",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^2.2",
"mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*",
"php-coveralls/php-coveralls": "1.1.0 || ^2.0",
"phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.36 || ^7.0",
"squizlabs/php_codesniffer": "^2.9 || ^3.5",
"tecnickcom/tcpdf": "6.*"
},
"suggest": {
"dompdf/dompdf": "Allows writing PDF",
"ext-gd2": "Allows adding images",
"ext-xmlwriter": "Allows writing OOXML and ODF",
"ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template",
"ext-zip": "Allows writing OOXML and ODF"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-develop": "0.19-dev"
}
},
"autoload": {
"psr-4": {
"PhpOffice\\PhpWord\\": "src/PhpWord"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"authors": [
{
"name": "Mark Baker"
},
{
"name": "Gabriel Bull",
"email": "me@gabrielbull.com",
"homepage": "http://gabrielbull.com/"
},
{
"name": "Franck Lefevre",
"homepage": "https://rootslabs.net/blog/"
},
{
"name": "Ivan Lanin",
"homepage": "http://ivan.lanin.org"
},
{
"name": "Roman Syroeshko",
"homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/"
},
{
"name": "Antoine de Troostembergh"
}
],
"description": "PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)",
"homepage": "http://phpoffice.github.io",
"keywords": [
"ISO IEC 29500",
"OOXML",
"Office Open XML",
"OpenDocument",
"OpenXML",
"PhpOffice",
"PhpWord",
"Rich Text Format",
"WordprocessingML",
"doc",
"docx",
"html",
"odf",
"odt",
"office",
"pdf",
"php",
"reader",
"rtf",
"template",
"template processor",
"word",
"writer"
],
"support": {
"issues": "https://github.com/PHPOffice/PHPWord/issues",
"source": "https://github.com/PHPOffice/PHPWord/tree/0.18.3"
},
"time": "2022-02-17T15:40:03+00:00"
},
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
"version": "1.8.1", "version": "1.8.1",

View File

@ -1,5 +1,5 @@
<template> <template>
<InertiaHead title="Dodawanie CV" /> <InertiaHead title="Edycja CV" />
<div class="mx-auto w-full max-w-7xl bg-white shadow-md"> <div class="mx-auto w-full max-w-7xl bg-white shadow-md">
<div class="p-4 sm:px-6"> <div class="p-4 sm:px-6">
<h2 class="text-lg font-medium leading-6 text-gray-900"> <h2 class="text-lg font-medium leading-6 text-gray-900">

Binary file not shown.