Skip to content

Commit

Permalink
Merge pull request #2 from sitegeist/uploadFieldsInclusion
Browse files Browse the repository at this point in the history
add failing migrations and include upload fields in the export
  • Loading branch information
hedayati-m committed Nov 17, 2023
2 parents ad4af7f + 28fa0a3 commit 22cbe53
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 35 deletions.
11 changes: 7 additions & 4 deletions Classes/Application/Controller/FormManagementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Sitegeist\StoneTablet\Domain\Form\FormRegistrationExportQuery;
use Sitegeist\StoneTablet\Domain\Form\FormRegistrationRepository;
use Sitegeist\StoneTablet\Domain\Form\FormWasNotFound;
use Sitegeist\StoneTablet\Domain\Archive;

class FormManagementController extends AbstractModuleController
{
Expand All @@ -27,9 +28,10 @@ class FormManagementController extends AbstractModuleController

#[Flow\Inject]
protected FormRegistrationRepository $formRegistrationRepository;

#[Flow\Inject]
protected FormDirectory $formDirectory;
#[Flow\Inject]
protected Archive $archive;

public function indexAction(): void
{
Expand Down Expand Up @@ -60,18 +62,19 @@ public function exportAction(string $formId, ?string $startDate, ?string $endDat
new \DateTimeImmutable(),
$registrations,
$formLocator,
$this->formDirectory
$this->formDirectory,
$this->archive
);


ob_clean();
$content = $export->createExcelContent();
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Type: application/zip");
header(
'Content-Disposition: attachment; filename='
. ($formLocator->title ?: $formLocator->formId) . '-Export-'
. ($startDate ? $startDate . '_' : '') . ($endDate ?: $export->exportDate->format('Y-m-d'))
. '.xlsx'
. '.zip'
);
header("Content-Length: " . strlen($content));
echo($content);
Expand Down
68 changes: 68 additions & 0 deletions Classes/Domain/Archive.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

/*
* This file is part of the Sitegeist.StoneTablet package.
*/

declare(strict_types=1);

namespace Sitegeist\StoneTablet\Domain;

use Neos\Flow\Annotations as Flow;
use Neos\Flow\ResourceManagement\ResourceRepository;
use Neos\Utility\Files;
use Sitegeist\StoneTablet\Domain\Form\RegisteredUploadField;

final class Archive
{
#[Flow\Inject]
protected ResourceRepository $resourceRepository;

public function exportResourceFromRegisteredUploadField(
RegisteredUploadField $registeredUploadField,
ExportDirectory $exportDirectory
): string {
$resourceSha1Hash = $registeredUploadField->extractSha1();

$uploadFile = $this->resourceRepository->findOneBySha1($resourceSha1Hash);

if ($uploadFile) {
$resourceStream = $uploadFile->getStream();

if($resourceStream) {
file_put_contents(
$exportDirectory->getUploadPath() . $registeredUploadField->extractExportFileName(),
stream_get_contents($resourceStream)
);
fclose($resourceStream);
}
return $uploadFile->getFilename();
}

return '';
}

public function compressExportDirectory(ExportDirectory $exportDirectory): ?string
{
$rootPath = realpath($exportDirectory->path);
$archivePath = $exportDirectory->path . 'Archive.zip';
$zip = new \ZipArchive();

if ($zip->open($archivePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
foreach (Files::readDirectoryRecursively($exportDirectory->path) as $filePath) {
if (!is_dir($filePath))
{
$relativePath = substr($filePath, strlen($rootPath) + 1);

// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}

$zip->close();
return $archivePath;
}

return null;
}
}
43 changes: 43 additions & 0 deletions Classes/Domain/ExportDirectory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/*
* This file is part of the Sitegeist.StoneTablet package.
*/

declare(strict_types=1);

namespace Sitegeist\StoneTablet\Domain;

use Neos\Flow\Annotations as Flow;
use Neos\Utility\Files;

#[Flow\Proxy(false)]
class ExportDirectory
{
public const EXPORT_ROOT = FLOW_PATH_DATA . 'Temporary/StoneTablet/';
public const UPLOADS = 'Uploads/';
public function __construct(
public readonly string $path,
) {
}

public static function create(): self {
$date = new \DateTime('now');
$directoryPathAndName = self::EXPORT_ROOT . 'Export-' . $date->format('Y-m-d_H-i') . '/';

if (file_exists($directoryPathAndName)) {
Files::removeDirectoryRecursively($directoryPathAndName);
}

Files::createDirectoryRecursively($directoryPathAndName . self::UPLOADS);

return new self(
$directoryPathAndName . '/'
);
}

public function getUploadPath(): string
{
return $this->path . self::UPLOADS;
}
}
1 change: 1 addition & 0 deletions Classes/Domain/Form/CellValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function __construct(
public static function fromFormData(array $formData, string $fieldName): self
{
$fieldValue = $formData[$fieldName] ?? null;

return new self(
$fieldValue
? is_array($fieldValue) ? implode("\n", $fieldValue) : $fieldValue
Expand Down
72 changes: 54 additions & 18 deletions Classes/Domain/Form/FormRegistrationExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
use Neos\Utility\Files;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as ExcelWriter;
use Sitegeist\StoneTablet\Domain\ExportDirectory;
use Sitegeist\StoneTablet\Domain\Archive;

#[Flow\Proxy(false)]
final class FormRegistrationExport
Expand All @@ -20,7 +22,8 @@ public function __construct(
public readonly \DateTimeImmutable $exportDate,
public readonly FormRegistrations $registrations,
public readonly FormLocator $formLocator,
public readonly FormDirectory $formDirectory
public readonly FormDirectory $formDirectory,
private readonly Archive $archive
) {
}

Expand Down Expand Up @@ -55,6 +58,8 @@ public function createExcelContent(): string
$headerRow = $spreadsheet->getActiveSheet()->getRowIterator(4)->current();
$currentRowIndex = $headerRow->getRowIndex();
$column = 'A';
$metaHeaderRow->getWorksheet()->getCell($column . $currentRowIndex)->setValue('Identifier');
$column++;
foreach ($fieldNames as $fieldName) {
$metaHeaderRow->getWorksheet()->getCell($column . $currentRowIndex)->setValue($fieldName);
$column++;
Expand All @@ -64,38 +69,69 @@ public function createExcelContent(): string
}
$currentRowIndex = 5;
$spreadsheet->getActiveSheet()->insertNewRowBefore(5, $this->registrations->count());
$exportDirectory = ExportDirectory::create();

foreach ($this->registrations as $registration) {
$column = 'A';
$currentRow = $spreadsheet->getActiveSheet()->getRowIterator($currentRowIndex)->current();
$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->setValue(
$registration->identifier
);
$column++;
$currentRegistrationFields = $registration->formData;

foreach ($fieldNames as $fieldName) {
$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->setValue(
CellValue::fromFormData($currentRegistrationFields, $fieldName)->value
);
$fieldValue = $currentRegistrationFields[$fieldName] ?? null;

if ($fieldValue && str_starts_with($fieldValue, RegisteredUploadField::CELL_PREFIX) ) {
$registeredUploadField = new RegisteredUploadField($fieldValue);

$fileName = $this->archive->exportResourceFromRegisteredUploadField(
$registeredUploadField,
$exportDirectory
);

$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->getHyperlink()->setUrl('./' . ExportDirectory::UPLOADS . $registeredUploadField->extractExportFileName());

$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->setValue(
$fileName
);
} else {
$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->setValue(
CellValue::fromFormData($currentRegistrationFields, $fieldName)->value
);
}

$column++;
}
$metaHeaderRow->getWorksheet()->getCell(
$column . $currentRowIndex
)->setValue(
$registration->recordedAt->format(FormRegistrationRepository::DATE_FORMAT)
);

$currentRowIndex++;
}

$date = new \DateTime('now');
$filePathAndName =
/** @phpstan-ignore-next-line */
FLOW_PATH_DATA .
'Temporary/Form-Export-'
. $date->format('Y-m-d_H-i') . '.xlsx';
$excelPathAndName = $exportDirectory->path . basename($exportDirectory->path) . '.xlsx';
$writer = new ExcelWriter($spreadsheet);
$writer->save($filePathAndName);
$result = Files::getFileContents($filePathAndName);
unlink($filePathAndName);
$writer->save($excelPathAndName);

$zipFilePath = $this->archive->compressExportDirectory($exportDirectory);

if ($zipFilePath) {
$result = Files::getFileContents($zipFilePath);
Files::removeDirectoryRecursively(ExportDirectory::EXPORT_ROOT);
return $result;
}

return $result;
return '';
}

/**
Expand Down
48 changes: 48 additions & 0 deletions Classes/Domain/Form/RegisteredUploadField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the Sitegeist.StoneTablet package.
*/

declare(strict_types=1);

namespace Sitegeist\StoneTablet\Domain\Form;

use Neos\Flow\Annotations as Flow;
use Neos\Flow\ResourceManagement\PersistentResource;

/**
* The PersistedUploadFile domain value object
*/
#[Flow\Proxy(false)]
final class RegisteredUploadField implements \Stringable
{
const CELL_PREFIX = '#upload_field_';
public function __construct(
public readonly string $value
) {
}
public static function fromResource(?PersistentResource $resource): self
{
return new self(
$resource ? self::CELL_PREFIX . $resource->getSha1() . '.' . $resource->getFileExtension() : ''
);
}
public function extractExportFileName(): string
{
return substr($this->value, strlen(self::CELL_PREFIX));
}

public function extractSha1(): string
{
return strtok(
substr($this->value, strlen(self::CELL_PREFIX)),
'.'
);
}

public function __toString(): string
{
return $this->value;
}
}
20 changes: 14 additions & 6 deletions Classes/Runtime/Action/RegisterFormAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@

use Neos\ContentRepository\Domain\Model\Node;
use Neos\Flow\Mvc\ActionResponse;
use Neos\Flow\ResourceManagement\PersistentResource;
use Neos\Flow\Utility\Algorithms;
use Neos\Fusion\Form\Runtime\Action\AbstractAction;
use Sitegeist\StoneTablet\Domain\Form\Field;
use Sitegeist\StoneTablet\Domain\Form\FormRegistration;
use Sitegeist\StoneTablet\Domain\Form\FormRegistrationRepository;
use Sitegeist\StoneTablet\Domain\Form\RegisteredUploadField;
use Sitegeist\StoneTablet\Domain\Archive;

class RegisterFormAction extends AbstractAction
{
public const DATE_FORMAT = 'Y-m-d';
public function __construct(
private readonly FormRegistrationRepository $formRegistrationRepository
private readonly FormRegistrationRepository $formRegistrationRepository,
private readonly Archive $archive
) {
}

Expand All @@ -29,7 +33,7 @@ public function perform(): ?ActionResponse
/** @var Node $formNode */
$formNode = $this->options['formNode'];

$formData = $this->prepareFormDataForSerialisation($this->options['formData']);
$formData = $this->prepareFormDataForSerialization($this->options['formData']);

$excludedFields = array_map(
fn($excludedField) => Field::fromArray($excludedField)->name,
Expand Down Expand Up @@ -58,12 +62,16 @@ public function perform(): ?ActionResponse
* @param array<string,mixed> $formData
* @return array<string,mixed>
*/
private function prepareFormDataForSerialisation(array $formData): array
private function prepareFormDataForSerialization(array $formData): array
{
return array_map(
fn (mixed $fieldValue) => $fieldValue instanceof \DateTimeInterface
? $fieldValue->format(self::DATE_FORMAT)
: $fieldValue,
fn (mixed $fieldValue) => match (true) {
$fieldValue instanceof \DateTimeInterface
=> $fieldValue->format(self::DATE_FORMAT),
$fieldValue instanceof PersistentResource
=> (string)RegisteredUploadField::fromResource($fieldValue),
default => $fieldValue
},
$formData
);
}
Expand Down

0 comments on commit 22cbe53

Please sign in to comment.