Skip to content

Commit 94459a1

Browse files
authored
Merge pull request hoogi91#50 from hoogi91/develop
Maintenance Release 2.1.0
2 parents 8cc24ff + 8369a84 commit 94459a1

50 files changed

Lines changed: 5139 additions & 6975 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040

4141
- name: Install project testing dependencies
4242
run: |
43+
rm composer.lock
4344
if [[ "${{ matrix.typo3_version }}" = *"dev"* ]]; then
4445
composer config minimum-stability dev;
4546
composer config prefer-stable true;

Classes/DataProcessing/SpreadsheetProcessor.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Hoogi91\Spreadsheets\Exception\InvalidDataSourceNameException;
99
use Hoogi91\Spreadsheets\Service\ExtractorService;
1010
use Hoogi91\Spreadsheets\Service\StyleService;
11+
use PhpOffice\PhpSpreadsheet\Reader\Exception as SpreadsheetReaderException;
1112
use TYPO3\CMS\Core\Page\PageRenderer;
1213
use TYPO3\CMS\Core\Utility\GeneralUtility;
1314
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -75,13 +76,10 @@ public function process(
7576
try {
7677
// get spreadsheet DSN value from content object to parse and render
7778
$dsnValue = DsnValueObject::createFromDSN($value);
78-
} catch (InvalidDataSourceNameException $exception) {
79+
$extraction = $this->extractorService->getDataByDsnValueObject($dsnValue, true);
80+
} catch (InvalidDataSourceNameException | SpreadsheetReaderException $exception) {
7981
// if DSN could not be parsed or is invalid the output is empty
80-
return $processedData;
81-
}
82-
83-
$extraction = $this->extractorService->getDataByDsnValueObject($dsnValue, true);
84-
if ($extraction === null) {
82+
// or the extraction failed
8583
return $processedData;
8684
}
8785

Classes/Domain/ValueObject/CellDataValueObject.php

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -273,16 +273,6 @@ public function getClass(): string
273273
return $cellClass;
274274
}
275275

276-
/**
277-
* @param string $name
278-
* @param mixed|null $default
279-
* @return mixed|null
280-
*/
281-
private function getMetaData(string $name, $default = null)
282-
{
283-
return $this->metaData[$name] ?? $default;
284-
}
285-
286276
/**
287277
* @inheritDoc
288278
*/
@@ -296,7 +286,7 @@ public function jsonSerialize()
296286
$data['col'] = $this->getColspan();
297287
}
298288

299-
$css = $this->getMetaData('backendCellClasses');
289+
$css = $this->metaData['backendCellClasses'] ?? null;
300290
if (empty($css) === false) {
301291
$data['css'] = implode('-', $css);
302292
}

Classes/Domain/ValueObject/DsnValueObject.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Hoogi91\Spreadsheets\Domain\ValueObject;
66

77
use Hoogi91\Spreadsheets\Exception\InvalidDataSourceNameException;
8+
use JsonSerializable;
89
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
910
use TYPO3\CMS\Core\Resource\FileReference;
1011
use TYPO3\CMS\Core\Resource\FileRepository;
@@ -15,7 +16,7 @@
1516
* Class DsnValueObject
1617
* @package Hoogi91\Spreadsheets\Domain\ValueObject
1718
*/
18-
class DsnValueObject
19+
class DsnValueObject implements JsonSerializable
1920
{
2021
/**
2122
* Legacy DSN pattern matches all strings like:
@@ -69,7 +70,7 @@ public function __construct(string $dsn)
6970
$this->legacyDSNParsing($dsn);
7071
} elseif (preg_match(self::DSN_PATTERN, $dsn) === 1) {
7172
$dsnData = parse_url($dsn);
72-
parse_str($dsnData['query'], $queryData);
73+
parse_str($dsnData['query'] ?? '', $queryData);
7374
if (MathUtility::canBeInterpretedAsInteger($dsnData['host'])) {
7475
/** @var FileRepository $fileRepository */
7576
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
@@ -103,10 +104,6 @@ public function __construct(string $dsn)
103104
private function legacyDSNParsing(string $dsn): void
104105
{
105106
[$file, $fullSelection] = GeneralUtility::trimExplode('|', $dsn, false, 2);
106-
if (empty($file)) {
107-
throw new InvalidDataSourceNameException('File reference is required in spreadsheet DSN!');
108-
}
109-
110107
if (strpos($file, 'file:') === 0 && (int)substr($file, 5) !== 0) {
111108
/** @var FileRepository $fileRepository */
112109
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
@@ -119,7 +116,7 @@ private function legacyDSNParsing(string $dsn): void
119116
throw new InvalidDataSourceNameException('File reference from DSN can not be parsed/evaluated!');
120117
}
121118

122-
if (empty($fullSelection) === false) {
119+
if (trim($fullSelection) !== '') {
123120
[$sheetIndex, $selection, $directionOfSelection] = GeneralUtility::trimExplode(
124121
'!',
125122
$fullSelection,
@@ -208,4 +205,12 @@ public function __toString()
208205
{
209206
return $this->getDsn();
210207
}
208+
209+
/**
210+
* @return string
211+
*/
212+
public function jsonSerialize(): string
213+
{
214+
return $this->getDsn();
215+
}
211216
}

Classes/Domain/ValueObject/StylesheetValueObject.php

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,8 @@ public static function create(array $styles): StylesheetValueObject
4141
*
4242
* @return string
4343
*/
44-
private function assembleStyles($styles = []): string
44+
private function assembleStyles(array $styles = []): string
4545
{
46-
if (empty($styles)) {
47-
return '';
48-
}
49-
5046
$pairs = [];
5147
foreach ($styles as $property => $value) {
5248
$pairs[] = $property . ':' . $value;
@@ -65,32 +61,20 @@ public function toInlineCSS(): string
6561
*/
6662
public function toCSS(?string $htmlIdentifier = null): string
6763
{
68-
if (empty($this->styles)) {
69-
return '';
70-
}
71-
7264
// write all styles with table selector prefix
7365
$content = '';
7466
foreach ($this->styles as $styleName => $styleDefinition) {
7567
if ($styleName !== 'html') {
7668
if (empty($htmlIdentifier) === false) {
77-
$content .= vsprintf(
78-
'#%s %s {%s}' . PHP_EOL,
79-
[
80-
$htmlIdentifier,
81-
$styleName,
82-
$this->assembleStyles($styleDefinition),
83-
]
84-
);
85-
} else {
86-
$content .= vsprintf(
87-
'%s {%s}' . PHP_EOL,
88-
[
89-
$styleName,
90-
$this->assembleStyles($styleDefinition),
91-
]
92-
);
69+
$content .= sprintf('#%s ', $htmlIdentifier);
9370
}
71+
$content .= vsprintf(
72+
'%s {%s}' . PHP_EOL,
73+
[
74+
$styleName,
75+
$this->assembleStyles($styleDefinition),
76+
]
77+
);
9478
}
9579
}
9680
return $content;

Classes/Form/Element/DataInputElement.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ public function __construct(NodeFactory $nodeFactory, array $data)
6060
$this->extractorService = GeneralUtility::makeInstance(ExtractorService::class);
6161
$this->config = $this->data['parameterArray']['fieldConf']['config'];
6262

63-
/** @var StandaloneView $view */
6463
$this->view = GeneralUtility::makeInstance(StandaloneView::class);
6564
$this->view->setTemplatePathAndFilename($this->getTemplatePath());
6665
$this->view->assign('inputSize', (int)$this->config['size'] ?: 0);
@@ -78,7 +77,7 @@ public function render(): array
7877
$resultArray = $this->initializeResultArray();
7978

8079
// upload fields hasn't been specified
81-
if (array_key_exists($this->config['uploadField'], $this->data['processedTca']['columns']) === false) {
80+
if (array_key_exists($this->config['uploadField'], $this->data['processedTca']['columns'] ?? []) === false) {
8281
$resultArray['html'] = $this->view->assign('missingUploadField', true)->render();
8382
return $resultArray;
8483
}
@@ -95,7 +94,7 @@ public function render(): array
9594
$resultArray['stylesheetFiles'] = ['EXT:spreadsheets/Resources/Public/Css/SpreadsheetDataInput.css'];
9695

9796
try {
98-
$valueObject = DsnValueObject::createFromDSN($this->data['parameterArray']['itemFormElValue']);
97+
$valueObject = DsnValueObject::createFromDSN($this->data['parameterArray']['itemFormElValue'] ?? '');
9998
} catch (InvalidDataSourceNameException $exception) {
10099
$valueObject = '';
101100
}
@@ -178,7 +177,7 @@ private function getFileReferencesSpreadsheetData(array $references): array
178177
$sheetData,
179178
static function (&$item) {
180179
if (is_string($item) && mb_detect_encoding($item, 'utf-8', true) === false) {
181-
$item = utf8_encode($item);
180+
$item = utf8_encode($item); // @codeCoverageIgnore
182181
}
183182
}
184183
);
@@ -217,8 +216,9 @@ private function getWorksheetDataFromSpreadsheet(Spreadsheet $spreadsheet): arra
217216
'name' => $worksheet->getTitle(),
218217
'cells' => $this->extractorService->rangeToCellArray($worksheet, $worksheetRange),
219218
];
220-
} catch (SpreadsheetException $e) {
219+
} catch (SpreadsheetException $e) { // @codeCoverageIgnoreStart
221220
// ignore sheet when an exception occurs
221+
// @codeCoverageIgnoreEnd
222222
}
223223
}
224224
return $sheetData;

Classes/Hooks/DataHandlerHook.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace Hoogi91\Spreadsheets\Hooks;
4+
5+
use TYPO3\CMS\Backend\Utility\BackendUtility;
6+
use TYPO3\CMS\Core\DataHandling\DataHandler;
7+
use TYPO3\CMS\Core\Resource\FileReference;
8+
use TYPO3\CMS\Core\Resource\FileRepository;
9+
use TYPO3\CMS\Core\Utility\GeneralUtility;
10+
11+
/**
12+
* Class DataHandlerHook
13+
* @package Hoogi91\Spreadsheets\Hooks
14+
*/
15+
class DataHandlerHook
16+
{
17+
private static $records = [];
18+
19+
/**
20+
* Post hook to set default spreadsheet selection for newly created items
21+
*
22+
* @param string|mixed $status Status which should be "new" to activate this hook
23+
* @param string|mixed $table Table which should be "tt_content" to activate this hook
24+
* @param int|string|mixed $id Temporary ID used to search for real new uid
25+
* @param array $fieldArray Field array that has been saved to database
26+
* @param DataHandler $dataHandler Data handler instance
27+
*
28+
* @return void
29+
*/
30+
public function processDatamap_afterDatabaseOperations( // @codingStandardsIgnoreLine
31+
$status,
32+
$table,
33+
$id,
34+
array $fieldArray,
35+
DataHandler $dataHandler
36+
): void {
37+
// skip processing for unknown uid, wrong table, status or not updated assets
38+
$uid = $dataHandler->substNEWwithIDs[$id] ?? (is_int($id) ? $id : null);
39+
if ($uid === null
40+
|| $table !== 'tt_content'
41+
|| !array_key_exists('tx_spreadsheets_assets', $fieldArray)
42+
|| !in_array($status, ['new', 'update'], true)) {
43+
return;
44+
}
45+
46+
// skip if not spreadsheet table or bodytext is already filled
47+
$CType = $fieldArray['CType'] ?? $this->getBackendRecordField($uid, 'CType');
48+
if ($CType !== 'spreadsheets_table') {
49+
return;
50+
}
51+
52+
// truncate bodytext after update if assets have been removed
53+
if ($fieldArray['tx_spreadsheets_assets'] === 0) {
54+
if ($status === 'update') {
55+
$dataHandler->updateDB('tt_content', $uid, ['bodytext' => '']);
56+
}
57+
return;
58+
}
59+
60+
/** @var FileRepository $fileRepository */
61+
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
62+
/** @var FileReference[] $relations */
63+
$relations = $fileRepository->findByRelation('tt_content', 'tx_spreadsheets_assets', $uid);
64+
if (empty($relations)) {
65+
return;
66+
}
67+
68+
// update bodytext to default file selection
69+
if (empty($this->getBackendRecordField($uid, 'bodytext')) === true) {
70+
$dataHandler->updateDB('tt_content', $uid, ['bodytext' => 'spreadsheet://' . $relations[0]->getUid()]);
71+
}
72+
}
73+
74+
/**
75+
* Get backend record field but load entry once
76+
*
77+
* @param int $uid UID of tt_content record
78+
* @param string $field Field to extract
79+
*
80+
* @return mixed|null
81+
*/
82+
private function getBackendRecordField(int $uid, string $field)
83+
{
84+
if (!isset(self::$records[$uid])) {
85+
self::$records[$uid] = BackendUtility::getRecord('tt_content', $uid); // @codeCoverageIgnore
86+
}
87+
return self::$records[$uid][$field] ?? null;
88+
}
89+
}

Classes/Service/CellService.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function __construct(StyleService $styleService)
5252

5353
/**
5454
* @param Cell $cell
55-
* @param callable $formatCallback
55+
* @param callable|null $formatCallback
5656
*
5757
* @return string
5858
*/
@@ -67,11 +67,9 @@ public function getFormattedValue(Cell $cell, callable $formatCallback = null):
6767
if ($value instanceof RichText) {
6868
$richTextValue = '';
6969
foreach ($value->getRichTextElements() as $element) {
70-
if ($element instanceof Run) {
71-
$richTextValue .= $this->getTextElementValue($element);
72-
} else {
73-
$richTextValue .= $element->getText();
74-
}
70+
$richTextValue .= $element instanceof Run
71+
? $this->getTextElementValue($element)
72+
: $element->getText();
7573
}
7674
$value = $richTextValue;
7775
} else {
@@ -89,7 +87,7 @@ public function getFormattedValue(Cell $cell, callable $formatCallback = null):
8987
*
9088
* @return string
9189
*/
92-
private function getTextElementValue($element): string
90+
private function getTextElementValue(Run $element): string
9391
{
9492
// evaluate text content and check if it is superscript or subscript
9593
$textContent = $element->getText();
@@ -116,7 +114,7 @@ private function getTextElementValue($element): string
116114
/**
117115
* @param string|int|float $value
118116
* @param Cell $cell
119-
* @param callable $callback
117+
* @param callable|null $callback
120118
*
121119
* @return string
122120
*/
@@ -153,6 +151,6 @@ private function formatString($value, Cell $cell, callable $callback = null): st
153151
return (string)$value;
154152
}
155153

156-
return (string)NumberFormat::toFormattedString($value, NumberFormat::FORMAT_GENERAL, $callback);
154+
return NumberFormat::toFormattedString($value, NumberFormat::FORMAT_GENERAL, $callback);
157155
}
158156
}

0 commit comments

Comments
 (0)