Skip to content

Commit cd195a3

Browse files
authored
Merge pull request hoogi91#583 from hoogi91/develop
Bugfix Release 4.0.2
2 parents 7e20b48 + aa70e8f commit cd195a3

15 files changed

Lines changed: 835 additions & 1445 deletions

File tree

.eslintignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

.eslintrc.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

.github/workflows/npm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- name: "Checkout"
3030
uses: "actions/checkout@v4"
3131

32-
- name: "Composer install"
32+
- name: "NPM install"
3333
uses: ./.github/actions/npm
3434
with:
3535
node-version: '${{ matrix.node-version }}'

Classes/Hooks/DataHandlerHook.php

Lines changed: 106 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Hoogi91\Spreadsheets\Hooks;
66

7+
use Hoogi91\Spreadsheets\Domain\ValueObject\DsnValueObject;
78
use TYPO3\CMS\Backend\Utility\BackendUtility;
89
use TYPO3\CMS\Core\Database\ConnectionPool;
910
use TYPO3\CMS\Core\DataHandling\DataHandler;
@@ -17,10 +18,38 @@ class DataHandlerHook
1718
*/
1819
private array $records = [];
1920

21+
/**
22+
* @var array<string, array<string, array<string, array<string>>>>
23+
*/
24+
private array $activationTypes = [];
25+
2026
public function __construct(
2127
private readonly FileRepository $fileRepository,
2228
private readonly ConnectionPool $connectionPool
2329
) {
30+
foreach ($GLOBALS['TCA'] as $table => $tca) {
31+
$table = (string)$table;
32+
foreach ($tca['columns'] ?? [] as $column => $conf) {
33+
if (
34+
isset($conf['config']['renderType'], $conf['config']['uploadField'])
35+
&& $conf['config']['renderType'] === 'spreadsheetInput'
36+
) {
37+
$this->activationTypes[$table]['*'][(string)$conf['config']['uploadField']][] = $column;
38+
}
39+
}
40+
41+
foreach ($GLOBALS['TCA'][$table]['types'] as $CType => $type) {
42+
$CType = (string)$CType;
43+
foreach ($type['columnsOverrides'] as $column => $conf) {
44+
if (
45+
isset($conf['config']['renderType'], $conf['config']['uploadField'])
46+
&& $conf['config']['renderType'] === 'spreadsheetInput'
47+
) {
48+
$this->activationTypes[$table][$CType][(string)$conf['config']['uploadField']][] = $column;
49+
}
50+
}
51+
}
52+
}
2453
}
2554

2655
/**
@@ -37,56 +66,107 @@ public function processDatamap_afterDatabaseOperations( // @codingStandardsIgnor
3766
array $fieldArray,
3867
DataHandler $dataHandler
3968
): void {
40-
// skip processing for unknown uid, wrong table, status or not updated assets
69+
// skip processing for not found uid or irrelevant status
4170
$uid = $dataHandler->substNEWwithIDs[$id] ?? (is_int($id) ? $id : null);
42-
if (
43-
$uid === null
44-
|| $table !== 'tt_content'
45-
|| !array_key_exists('tx_spreadsheets_assets', $fieldArray)
46-
|| !in_array($status, ['new', 'update'], true)
47-
) {
71+
if ($uid === null || !is_string($table) || !in_array($status, ['new', 'update'], true)) {
4872
return;
4973
}
5074

51-
// skip if not spreadsheet table or bodytext is already filled
52-
$CType = $fieldArray['CType'] ?? $this->getBackendRecordField($uid, 'CType');
53-
if (!in_array($CType, ['spreadsheets_table', 'spreadsheets_tabs'], true)) {
75+
// ignore if handler should not process for table and/or CType
76+
$CType = $fieldArray['CType'] ?? $this->getBackendRecordField($uid, $table, 'CType');
77+
if (!isset($this->activationTypes[$table]['*']) && !isset($this->activationTypes[$table][$CType])) {
5478
return;
5579
}
5680

57-
// truncate bodytext after update if assets have been removed
58-
if ($fieldArray['tx_spreadsheets_assets'] === 0) {
59-
if ($status === 'update') {
60-
$this->connectionPool
61-
->getConnectionForTable('tt_content')
62-
->update('tt_content', ['bodytext' => ''], ['uid' => $uid]);
81+
$activationConfig = $this->activationTypes[$table][$CType] ?? $this->activationTypes[$table]['*'];
82+
foreach ($activationConfig as $uploadField => $renderFields) {
83+
// truncate render fields after update if assets have been removed
84+
if ($fieldArray[$uploadField] === 0) {
85+
if ($status === 'update') {
86+
$this->connectionPool
87+
->getConnectionForTable($table)
88+
->update($table, array_fill_keys($renderFields, ''), ['uid' => $uid]);
89+
}
90+
91+
continue;
6392
}
6493

65-
return;
94+
// if upload fields was filled we get it's relations and start to update all render fields if required
95+
/** @var array<FileReference> $relations */
96+
$relations = $this->fileRepository->findByRelation($table, $uploadField, $uid);
97+
foreach ($renderFields as $renderField) {
98+
$this->setSpreadsheetValue($uid, $table, $status, $renderField, $relations);
99+
}
66100
}
101+
}
67102

68-
/** @var array<FileReference> $relations */
69-
$relations = $this->fileRepository->findByRelation('tt_content', 'tx_spreadsheets_assets', $uid);
103+
/**
104+
* @param int $uid UID of chart record
105+
* @param string $table Table to update
106+
* @param string $status Status of current record update
107+
* @param string $field Field to update spreadsheet value
108+
* @param array<FileReference> $relations File relations found
109+
*
110+
*/
111+
private function setSpreadsheetValue(
112+
int $uid,
113+
string $table,
114+
string $status,
115+
string $field,
116+
array $relations
117+
): void {
70118
if (empty($relations)) {
71119
return;
72120
}
73121

74-
// update bodytext to default file selection
75-
if (empty($this->getBackendRecordField($uid, 'bodytext')) === true) {
122+
// if backend record field is currently empty we pre-select with first relation
123+
$fieldValue = $this->getBackendRecordField($uid, $table, $field);
124+
if (empty($fieldValue) === true) {
76125
$this->connectionPool
77-
->getConnectionForTable('tt_content')
78-
->update('tt_content', ['bodytext' => 'spreadsheet://' . $relations[0]->getUid()], ['uid' => $uid]);
126+
->getConnectionForTable($table)
127+
->update($table, [$field => 'spreadsheet://' . $relations[0]->getUid()], ['uid' => $uid]);
128+
} elseif ($status === 'new' && is_string($fieldValue)) {
129+
$dsn = $this->getTranslatedSpreadsheetDsn(
130+
DsnValueObject::createFromDSN($fieldValue),
131+
$relations
132+
);
133+
if ($dsn !== null) {
134+
$this->connectionPool
135+
->getConnectionForTable($table)
136+
->update($table, [$field => $dsn], ['uid' => $uid]);
137+
}
138+
}
139+
}
140+
141+
/**
142+
* @param DsnValueObject $dsn Original DSN
143+
* @param array<FileReference> $references File relations found
144+
*
145+
*/
146+
private function getTranslatedSpreadsheetDsn(DsnValueObject $dsn, array $references): ?string
147+
{
148+
foreach ($references as $reference) {
149+
if ($reference->getReferenceProperty('l10n_parent') === $dsn->getFileReference()) {
150+
return str_replace(
151+
'spreadsheet://' . $dsn->getFileReference(),
152+
'spreadsheet://' . $reference->getUid(),
153+
$dsn->getDsn()
154+
);
155+
}
79156
}
157+
158+
return null;
80159
}
81160

82161
/**
83-
* @param int $uid UID of tt_content record
162+
* @param int $uid UID of record
163+
* @param string $table Table to get record from
84164
* @param string $field Field to extract
85165
*/
86-
private function getBackendRecordField(int $uid, string $field): mixed
166+
private function getBackendRecordField(int $uid, string $table, string $field): mixed
87167
{
88168
if (!isset($this->records[$uid])) {
89-
$this->records[$uid] = BackendUtility::getRecord('tt_content', $uid); // @codeCoverageIgnore
169+
$this->records[$uid] = BackendUtility::getRecord($table, $uid); // @codeCoverageIgnore
90170
}
91171

92172
return $this->records[$uid][$field] ?? null;

Resources/Private/Assets/JavaScript/dsn.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {colHeaderToIndex} from "./helper";
1+
import {colHeaderToIndex} from "./helper.js";
22

33
export default class DSN {
44
constructor(value) {

Resources/Private/Assets/JavaScript/main.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import DSN from './dsn';
2-
import Renderer from './renderer';
3-
import Spreadsheet from './spreadsheet';
4-
import Selector from "./selector";
1+
import DSN from './dsn.js';
2+
import Renderer from './renderer.js';
3+
import Spreadsheet from './spreadsheet.js';
4+
import Selector from "./selector.js";
55
import DocumentService from 'DocumentService';
66

77
class SpreadsheetDataInput {

Resources/Private/Assets/JavaScript/renderer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import DSN from "./dsn";
2-
import {colHeaderByIndex} from "./helper";
1+
import DSN from "./dsn.js";
2+
import {colHeaderByIndex} from "./helper.js";
33

44
export default class Renderer {
55
constructor(sheetWrapper, tableWrapper) {

Resources/Private/Assets/JavaScript/selector.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {calculateCellIndexes, cellRepresentation, throttle, unselectEverything} from "./helper";
1+
import {calculateCellIndexes, cellRepresentation, throttle, unselectEverything} from "./helper.js";
22

33
export default class Selector {
44
constructor(tableWrapper) {

Resources/Private/Assets/JavaScript/spreadsheet.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import DSN from './dsn';
1+
import DSN from './dsn.js';
22

33
export default class Spreadsheet {
44
constructor(dsn, data) {

0 commit comments

Comments
 (0)