Add table export
continuous-integration/drone/push Build is failing Details

This commit is contained in:
philipp lang 2024-06-30 23:36:44 +02:00
parent 2425ff6638
commit ae450ef9ae
10 changed files with 436 additions and 5 deletions

3
.gitmodules vendored
View File

@ -17,3 +17,6 @@
[submodule "packages/flysystem-webdav"]
path = packages/flysystem-webdav
url = https://github.com/zoomyboy/flysystem-webdav.git
[submodule "packages/table-document"]
path = packages/table-document
url = https://git.zoomyboy.de/zoomyboy/table-document.git

View File

@ -2,6 +2,8 @@
namespace App\Fileshare\Data;
use App\Fileshare\Models\Fileshare;
use Illuminate\Filesystem\FilesystemAdapter;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Attributes\MapOutputName;
use Spatie\LaravelData\Data;
@ -15,4 +17,14 @@ class FileshareResourceData extends Data
public function __construct(public int $connectionId, public string $resource)
{
}
public function getConnection(): Fileshare
{
return Fileshare::find($this->connectionId);
}
public function getStorage(): FilesystemAdapter
{
return $this->getConnection()->type->getFilesystem();
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace App\Form\Actions;
use App\Form\Models\Form;
use App\Group;
use Illuminate\Support\Collection;
use Lorisleiva\Actions\Concerns\AsAction;
use Zoomyboy\TableDocument\SheetData;
use Zoomyboy\TableDocument\TableDocumentData;
class ExportSyncAction
{
use AsAction;
public Form $form;
public function handle(Form $form)
{
$this->form = $form;
if (!$form->export->root) {
return;
}
$storage = $form->export->root->getStorage();
$storage->put($form->export->root->resource . '/Anmeldungen ' . $form->name . '.xlsx', file_get_contents($this->allSheet($this->form->participants)->compile($this->tempPath())));
if ($form->export->toGroupField) {
foreach ($form->participants->groupBy(fn ($participant) => $participant->data[$form->export->toGroupField]) as $groupId => $participants) {
$group = Group::find($groupId);
if (!$group?->fileshare) {
continue;
}
$group->fileshare->getStorage()->put($group->fileshare->resource . '/Anmeldungen ' . $form->name . '.xlsx', file_get_contents($this->allSheet($participants)->compile($this->tempPath())));
}
}
}
public function asJob(int $formId): void
{
$this->handle(Form::find($formId));
}
private function allSheet(Collection $participants): TableDocumentData
{
$document = TableDocumentData::from(['title' => 'Anmeldungen für ' . $this->form->name, 'sheets' => []]);
$headers = $this->form->getFields()->map(fn ($field) => $field->name)->toArray();
$document->addSheet(SheetData::from([
'header' => $headers,
'data' => $participants
->map(fn ($participant) => $this->form->getFields()->map(fn ($field) => $participant->getFields()->find($field)->presentRaw())->toArray())
->toArray(),
'name' => 'Alle',
]));
if ($this->form->export->groupBy) {
$groups = $participants->groupBy(fn ($participant) => $participant->getFields()->findByKey($this->form->export->groupBy)->presentRaw());
foreach ($groups as $name => $participants) {
$document->addSheet(SheetData::from([
'header' => $headers,
'data' => $participants
->map(fn ($participant) => $this->form->getFields()->map(fn ($field) => $participant->getFields()->find($field)->presentRaw())->toArray())
->toArray(),
'name' => $name,
]));
}
$document->addSheet(SheetData::from([
'header' => ['Wert', 'Anzahl'],
'data' => $groups->map(fn ($participants, $name) => [$name, (string) count($participants)])->toArray(),
'name' => 'Statistik',
]));
}
return $document;
}
private function tempPath(): string
{
return sys_get_temp_dir() . '/' . str()->uuid()->toString();
}
}

View File

@ -32,6 +32,7 @@ class RegisterAction
$form->getFields()->each(fn ($field) => $field->afterRegistration($form, $participant, $input));
$participant->sendConfirmationMail();
ExportSyncAction::dispatch($form->id);
return $participant;
}

View File

@ -104,10 +104,7 @@ abstract class Field extends Data
];
}
/**
* @return mixed
*/
public function presentRaw()
public function presentRaw(): string
{
return $this->getPresenter()->present($this->value);
}

View File

@ -14,6 +14,13 @@
"symlink": true
}
},
{
"type": "path",
"url": "./packages/table-document",
"options": {
"symlink": true
}
},
{
"type": "path",
"url": "./packages/flysystem-webdav",
@ -69,6 +76,7 @@
"league/flysystem-webdav": "dev-master as 3.28.0",
"zoomyboy/osm": "1.0.3",
"zoomyboy/phone": "^1.0",
"zoomyboy/table-document": "dev-master as 1.0",
"zoomyboy/tex": "dev-main as 1.0"
},
"require-dev": {

251
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "552ce1f9c6448e20c08c2b3baca394df",
"content-hash": "7541aa772bfd34e379ec31ce8cefdb58",
"packages": [
{
"name": "amphp/amp",
@ -5205,6 +5205,113 @@
],
"time": "2023-06-21T14:59:35+00:00"
},
{
"name": "markbaker/complex",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
},
"time": "2022-12-06T16:21:08+00:00"
},
{
"name": "markbaker/matrix",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Matrix\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@demon-angel.eu"
}
],
"description": "PHP Class for working with matrices",
"homepage": "https://github.com/MarkBaker/PHPMatrix",
"keywords": [
"mathematics",
"matrix",
"vector"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
},
"time": "2022-12-02T22:17:43+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.22.3",
@ -7136,6 +7243,110 @@
},
"time": "2024-02-23T11:10:43+00:00"
},
{
"name": "phpoffice/phpspreadsheet",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e",
"reference": "dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0",
"php": "^8.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
"dompdf/dompdf": "^2.0",
"friendsofphp/php-cs-fixer": "^3.2",
"mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5"
},
"suggest": {
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
"ext-intl": "PHP Internationalization Functions",
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
},
"type": "library",
"autoload": {
"psr-4": {
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maarten Balliauw",
"homepage": "https://blog.maartenballiauw.be"
},
{
"name": "Mark Baker",
"homepage": "https://markbakeruk.net"
},
{
"name": "Franck Lefevre",
"homepage": "https://rootslabs.net"
},
{
"name": "Erik Tilt"
},
{
"name": "Adrien Crivelli"
}
],
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
"keywords": [
"OpenXML",
"excel",
"gnumeric",
"ods",
"php",
"spreadsheet",
"xls",
"xlsx"
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.1.0"
},
"time": "2024-05-11T04:17:56+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.9.2",
@ -14154,6 +14365,37 @@
"description": "Phone number formatting",
"time": "2023-03-02T23:22:08+00:00"
},
{
"name": "zoomyboy/table-document",
"version": "dev-master",
"dist": {
"type": "path",
"url": "./packages/table-document",
"reference": "c478784bbb26d7dc28c08670322dbf3b0d845f8c"
},
"require": {
"laravel/framework": "^9.0",
"phpoffice/phpspreadsheet": "^2.1",
"spatie/laravel-data": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Zoomyboy\\TableDocument\\": "src/"
}
},
"authors": [
{
"name": "Philipp Lang",
"email": "philipp@zoomyboy.de"
}
],
"description": "Table document creator",
"transport-options": {
"symlink": true,
"relative": true
}
},
{
"name": "zoomyboy/tex",
"version": "dev-main",
@ -15877,6 +16119,12 @@
"alias": "1.0",
"alias_normalized": "1.0.0.0"
},
{
"package": "zoomyboy/table-document",
"version": "9999999-dev",
"alias": "1.0",
"alias_normalized": "1.0.0.0"
},
{
"package": "zoomyboy/tex",
"version": "dev-main",
@ -15889,6 +16137,7 @@
"zoomyboy/laravel-nami": 20,
"zoomyboy/medialibrary-helper": 20,
"league/flysystem-webdav": 20,
"zoomyboy/table-document": 20,
"zoomyboy/tex": 20
},
"prefer-stable": true,

@ -0,0 +1 @@
Subproject commit c1d0221dcd2b4200b3ff17747e31f451fcc749f0

View File

@ -2,6 +2,8 @@
namespace Tests\Feature\Form;
use App\Form\Actions\ExportAction;
use App\Form\Actions\ExportSyncAction;
use App\Form\Enums\NamiType;
use App\Form\Enums\SpecialType;
use App\Form\Mails\ConfirmRegistrationMail;
@ -41,6 +43,7 @@ class FormRegisterActionTest extends FormTestCase
]),
])
->create();
ExportSyncAction::shouldRun()->once()->with($form->id);
$this->register($form, ['vorname' => 'Max', 'nachname' => 'Muster', 'spitzname' => 'Abraham'])
->assertOk();

View File

@ -0,0 +1,70 @@
<?php
namespace Tests\Fileshare;
use App\Fileshare\ConnectionTypes\OwncloudConnection;
use App\Fileshare\Data\FileshareResourceData;
use App\Fileshare\Models\Fileshare;
use App\Form\Actions\ExportSyncAction;
use App\Form\Data\ExportData;
use App\Form\Models\Form;
use App\Form\Models\Participant;
use App\Group;
use Tests\FileshareTestCase;
use Tests\Lib\CreatesFormFields;
class ExportSyncActionTest extends FileshareTestCase
{
use CreatesFormFields;
public function testItDoesntUploadFileWhenNoExportGiven(): void
{
$form = Form::factory()->fields([
$this->textField('vorname'),
$this->textField('nachname'),
])->create();
ExportSyncAction::run($form);
$this->assertTrue(true);
}
public function testItUploadsRootFile(): void
{
$this->withoutExceptionHandling()->withOwncloudUser('badenpowell', 'secret')->withDirs('badenpowell', ['/abc']);
$connection = Fileshare::factory()
->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')]))
->create();
$form = Form::factory()->name('Formular')->fields([
$this->textField('vorname'),
$this->textField('nachname'),
])->export(ExportData::from(['root' => FileshareResourceData::from(['connection_id' => $connection->id, 'resource' => '/abc'])]))->create();
Participant::factory()->for($form)->data(['firstname' => 'AAA', 'lastname' => 'BBB'])->create();
ExportSyncAction::run($form);
$this->assertEquals(['abc/Anmeldungen Formular.xlsx'], $connection->type->getFilesystem()->files('/abc'));
$this->assertTrue(true);
}
public function testItUploadsGroupFile(): void
{
$this->withoutExceptionHandling()->withOwncloudUser('badenpowell', 'secret')->withDirs('badenpowell', ['/abc', '/stamm']);
$connection = Fileshare::factory()
->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')]))
->create();
$group = Group::factory()->create(['fileshare' => FileshareResourceData::from(['connection_id' => $connection->id, 'resource' => '/stamm'])]);
$form = Form::factory()->name('Formular')->fields([
$this->textField('vorname')->name('Vorname'),
$this->textField('nachname')->name('Nachname'),
$this->groupField('stamm')->name('Stamm'),
])->export(ExportData::from(['to_group_field' => 'stamm', 'group_by' => 'vorname', 'root' => FileshareResourceData::from(['connection_id' => $connection->id, 'resource' => '/abc'])]))->create();
Participant::factory()->for($form)->data(['vorname' => 'AAA', 'nachname' => 'BBB', 'stamm' => $group->id])->create();
Participant::factory()->for($form)->data(['vorname' => 'CCC', 'nachname' => 'DDD', 'stamm' => null])->create();
ExportSyncAction::run($form);
$this->assertEquals(['stamm/Anmeldungen Formular.xlsx'], $connection->type->getFilesystem()->files('/stamm'));
$this->assertTrue(true);
}
}