Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 47 additions & 42 deletions Classes/Form/Element/DataInputElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
use TYPO3\CMS\Backend\Form\NodeFactory;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
Expand All @@ -23,78 +22,84 @@ class DataInputElement extends AbstractFormElement
{
private const DEFAULT_TEMPLATE_PATH = 'EXT:spreadsheets/Resources/Private/Templates/FormElement/DataInput.html';

private readonly ReaderService $readerService;

private readonly ExtractorService $extractorService;
private ReaderService $readerService;
private ExtractorService $extractorService;
private StandaloneView $view;

/**
* @var array<string, string>
*/
private array $config;

private readonly StandaloneView $view;

/**
* @param array<mixed> $data
*/
public function __construct(NodeFactory $nodeFactory, array $data)
private array $config = [];

public function __construct(
ReaderService $readerService,
ExtractorService $extractorService,
StandaloneView $view
) {
$this->readerService = $readerService;
$this->extractorService = $extractorService;
$this->view = $view;
}
public function setData(array $data): void
{
parent::__construct($nodeFactory, $data);
$this->readerService = GeneralUtility::makeInstance(ReaderService::class);
$this->extractorService = GeneralUtility::makeInstance(ExtractorService::class);
$this->config = $this->data['parameterArray']['fieldConf']['config'] ?? [];

$this->view = GeneralUtility::makeInstance(StandaloneView::class);
$this->view->setTemplatePathAndFilename($this->getTemplatePath());
$this->view->assign('inputSize', (int)($this->config['size'] ?? 0));
$this->data = $data;
}

/**
* @return array<mixed> As defined in initializeResultArray() of AbstractNode
* @return array<mixed> As defined in initializeResultArray() of AbstractFormElement
*/
public function render(): array
{
// get initialize result array from parent abstract node
// Access the $data array
$data = $this->data;

// Initialize the result array
$resultArray = $this->initializeResultArray();

// upload fields hasn't been specified
if (array_key_exists($this->config['uploadField'], $this->data['processedTca']['columns'] ?? []) === false) {
// Initialize configuration
$this->config = $data['parameterArray']['fieldConf']['config'] ?? [];

// Set the template path
$this->view->setTemplatePathAndFilename($this->getTemplatePath());
$this->view->assign('inputSize', (int)($this->config['size'] ?? 0));

// Check if upload field is specified
if (!isset($this->config['uploadField']) || !array_key_exists($this->config['uploadField'], $data['processedTca']['columns'] ?? [])) {
$resultArray['html'] = $this->view->assign('missingUploadField', true)->render();

return $resultArray;
}

// return alert if non valid file references were uploaded
// Get valid file references
$references = $this->getValidFileReferences($this->config['uploadField']);
if (empty($references)) {
$resultArray['html'] = $this->view->assign('nonValidReferences', true)->render();

return $resultArray;
}

// register additional assets only when input will be rendered
$resultArray['requireJsModules'][] = JavaScriptModuleInstruction::forRequireJS(
'TYPO3/CMS/Spreadsheets/SpreadsheetDataInput'
)->instance($this->data['parameterArray']['itemFormElName'] ?? null);
$resultArray['stylesheetFiles'] = ['EXT:spreadsheets/Resources/Public/Css/SpreadsheetDataInput.css'];
// Register additional assets only when input will be rendered
/** @var PageRenderer $pageRenderer */
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
$pageRenderer->loadJavaScriptModule('@hoogi91/spreadsheets/SpreadsheetDataInput.js');
$pageRenderer->addCssFile('EXT:spreadsheets/Resources/Public/Css/SpreadsheetDataInput.css');

try {
$valueObject = DsnValueObject::createFromDSN($this->data['parameterArray']['itemFormElValue'] ?? '');
$valueObject = DsnValueObject::createFromDSN($data['parameterArray']['itemFormElValue'] ?? '');
} catch (InvalidDataSourceNameException) {
$valueObject = '';
}

$this->view->assignMultiple(
[
'inputName' => $this->data['parameterArray']['itemFormElName'] ?? null,
'inputName' => $data['parameterArray']['itemFormElName'] ?? null,
'config' => $this->config,
'sheetFiles' => $references,
'sheetData' => $this->getFileReferencesSpreadsheetData($references),
'valueObject' => $valueObject,
]
);

// render view and return result array
// Render view and return result array
$resultArray['html'] = $this->view->render();

return $resultArray;
Expand All @@ -107,7 +112,7 @@ private function getTemplatePath(): string
}

$templatePath = GeneralUtility::getFileAbsFileName($this->config['template']);
if (is_file($templatePath) === false) {
if (!is_file($templatePath)) {
return GeneralUtility::getFileAbsFileName(self::DEFAULT_TEMPLATE_PATH);
}

Expand All @@ -128,7 +133,7 @@ private function getValidFileReferences(string $fieldName): array
return [];
}

// filter references by allowed types
// Filter references by allowed types
return array_filter(
$references,
static fn ($reference) => in_array($reference->getExtension(), ReaderService::ALLOWED_EXTENSIONS, true)
Expand All @@ -141,16 +146,16 @@ private function getValidFileReferences(string $fieldName): array
*/
private function getFileReferencesSpreadsheetData(array $references): array
{
// read all spreadsheet from valid file references and filter out invalid references
// Read all spreadsheets from valid file references and filter out invalid references
$spreadsheets = $this->getSpreadsheetsByFileReferences($references);

// get data from file references
// Get data from file references
$sheetData = [];
foreach ($spreadsheets as $fileUid => $spreadsheet) {
$sheetData[$fileUid] = $this->getWorksheetDataFromSpreadsheet($spreadsheet);
}

// convert whole sheet data content to UTF-8
// Convert whole sheet data content to UTF-8
array_walk_recursive(
$sheetData,
static function (&$item): void {
Expand All @@ -174,7 +179,7 @@ private function getSpreadsheetsByFileReferences(array $references): array
try {
$spreadsheets[$reference->getUid()] = $this->readerService->getSpreadsheet($reference);
} catch (ReaderException) {
// ignore reading non-existing or invalid file reference
// Ignore reading non-existing or invalid file reference
}
}

Expand All @@ -195,7 +200,7 @@ private function getWorksheetDataFromSpreadsheet(Spreadsheet $spreadsheet): arra
'cells' => $this->extractorService->rangeToCellArray($worksheet, $worksheetRange),
];
} catch (SpreadsheetException) {
// ignore sheet when an exception occurs
// Ignore sheet when an exception occurs
}
}

Expand Down
15 changes: 8 additions & 7 deletions Classes/Service/ExtractorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@

namespace Hoogi91\Spreadsheets\Service;

use Hoogi91\Spreadsheets\Domain\ValueObject;

use Iterator;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use PhpOffice\PhpSpreadsheet\Reader\Exception as SpreadsheetReaderException;
use PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Column;
use PhpOffice\PhpSpreadsheet\Worksheet\Row;
use Hoogi91\Spreadsheets\Domain\ValueObject;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use PhpOffice\PhpSpreadsheet\Reader\Exception as SpreadsheetReaderException;
use TYPO3\CMS\Core\Http\ApplicationType;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Resource\ResourceFactory;

class ExtractorService
{
Expand All @@ -28,7 +29,7 @@ public function __construct(
private readonly SpanService $spanService,
private readonly RangeService $rangeService,
private readonly ValueMappingService $mappingService,
private readonly FileRepository $fileRepository
private readonly ResourceFactory $resourceFactory
) {
}

Expand All @@ -41,7 +42,7 @@ public function getDataByDsnValueObject(
bool $returnCellRef = false
): ValueObject\ExtractionValueObject {
$spreadsheet = $this->readerService->getSpreadsheet(
$this->fileRepository->findFileReferenceByUid($dsnValue->getFileReference())
$this->resourceFactory->getFileReferenceObject($dsnValue->getFileReference())
);

try {
Expand All @@ -65,7 +66,7 @@ public function getDataByDsnValueObject(
);

return ValueObject\ExtractionValueObject::create($spreadsheet, $cellData);
} catch (SpreadsheetException) {
} catch (SpreadsheetException) {
return ValueObject\ExtractionValueObject::create($spreadsheet, []);
}
}
Expand Down
12 changes: 12 additions & 0 deletions Configuration/JavaScriptModules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

return [
// required import configurations of other extensions,
// in case a module imports from another package
'dependencies' => ['backend'],
'imports' => [
// recursive definiton, all *.js files in this folder are import-mapped
// trailing slash is required per importmap-specification
'@hoogi91/spreadsheets/' => 'EXT:spreadsheets/Resources/Public/JavaScript/',
],
];
6 changes: 6 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ services:

Hoogi91\Spreadsheets\Service\ReaderService:
public: true

Hoogi91\Spreadsheets\Form\Element\DataInputElement:
arguments:
$readerService: '@Hoogi91\Spreadsheets\Service\ReaderService'
$extractorService: '@Hoogi91\Spreadsheets\Service\ExtractorService'
$view: '@TYPO3\CMS\Fluid\View\StandaloneView'
31 changes: 16 additions & 15 deletions Configuration/TCA/Overrides/tt_content.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,29 @@
);
}

// add own assets upload field
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns($table, [
'tx_spreadsheets_assets' => [
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'tx_spreadsheets_assets',
[
'foreign_table' => 'sys_file_reference',
'appearance' => [
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.asset_references.addFileReference',
],
'overrideChildTca' => [
'types' => [
'0' => [
'showitem' => '--palette--;;filePalette',
],
'exclude' => 1,
'label' => 'LLL:EXT:' . $extKey . '/Resources/Private/Language/locallang.xlf:tx_spreadsheets_assets.label',
'config' => [
'type' => 'file',
'appearance' => [
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.asset_references.addFileReference',
],
'overrideChildTca' => [
'types' => [
\TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [
'showitem' => '--palette--;;filePalette',
],
],
],
implode(',', \Hoogi91\Spreadsheets\Service\ReaderService::ALLOWED_EXTENSIONS)
),
'allowed' => implode(',', \Hoogi91\Spreadsheets\Service\ReaderService::ALLOWED_EXTENSIONS),
'maxitems' => 1, // Adjust this based on how many items can be uploaded
],
],
'tx_spreadsheets_ignore_styles' => [
'exclude' => 1,
'label' => 'LLL:EXT:' . $extKey . '/Resources/Private/Language/locallang.xlf:tca.tx_spreadsheets_ignore_styles.label',
'config' => [
'type' => 'check',
'items' => [
Expand Down
5 changes: 5 additions & 0 deletions Configuration/page.tsconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

// add content element to insert tables in content element wizard
// register template for backend preview rendering
@import 'EXT:spreadsheets/Configuration/PageTSconfig/NewContentElementWizard.typoscript'
@import 'EXT:spreadsheets/Configuration/PageTSconfig/BackendPreview.typoscript'
2 changes: 1 addition & 1 deletion Resources/Private/Assets/JavaScript/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import DSN from './dsn.js';
import Renderer from './renderer.js';
import Spreadsheet from './spreadsheet.js';
import Selector from "./selector.js";
import DocumentService from 'DocumentService';
import DocumentService from '@typo3/core/document-service.js';

class SpreadsheetDataInput {
constructor(element) {
Expand Down
Loading