wip
This commit is contained in:
parent
22c5f7bb54
commit
37d9404226
140
app/Domain/ResumeGenerator.php
Normal file
140
app/Domain/ResumeGenerator.php
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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
176
composer.lock
generated
@ -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",
|
||||||
|
@ -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">
|
||||||
|
BIN
resources/views/docx/resume_eng.docx
Normal file
BIN
resources/views/docx/resume_eng.docx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user