Skip to content

Commit

Permalink
[!!!][TASK] Add native types to CsvUtility
Browse files Browse the repository at this point in the history
Also, first class callable syntax is added for the csvValues
method.

Resolves: #97207
Related: #97210
Related: #97372
Releases: main
Change-Id: Ib37a497c8df38fa9ef2f071c10439de4d269b25c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74286
Tested-by: Nikita Hovratov <nikita.h@live.de>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
  • Loading branch information
Crell authored and sbuerk committed May 6, 2022
1 parent ffc5261 commit 8d2e34b
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 29 deletions.
40 changes: 17 additions & 23 deletions typo3/sysext/core/Classes/Utility/CsvUtility.php
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
Expand Down Expand Up @@ -49,7 +51,7 @@ class CsvUtility
* @param int $maximumColumns The maximum amount of columns
* @return array
*/
public static function csvToArray($input, $fieldDelimiter = ',', $fieldEnclosure = '"', $maximumColumns = 0)
public static function csvToArray(string $input, string $fieldDelimiter = ',', string $fieldEnclosure = '"', int $maximumColumns = 0): array
{
$multiArray = [];
$maximumCellCount = 0;
Expand Down Expand Up @@ -97,33 +99,30 @@ public static function csvToArray($input, $fieldDelimiter = ',', $fieldEnclosure
* @param int $type Output behaviour concerning potentially harmful control literals
* @return string A single line of CSV
*/
public static function csvValues(array $row, string $delim = ',', string $quote = '"', int $type = self::TYPE_REMOVE_CONTROLS)
public static function csvValues(array $row, string $delim = ',', string $quote = '"', int $type = self::TYPE_REMOVE_CONTROLS): string
{
$resource = fopen('php://temp', 'w');
if (!is_resource($resource)) {
throw new \RuntimeException('Cannot open temporary data stream for writing', 1625556521);
}
$modifier = CsvStreamFilter::applyStreamFilter($resource, false);
array_map([self::class, 'assertCellValueType'], $row);
array_map(self::assertCellValueType(...), $row);
if ($type === self::TYPE_REMOVE_CONTROLS) {
$row = array_map([self::class, 'removeControlLiterals'], $row);
$row = array_map(self::removeControlLiterals(...), $row);
} elseif ($type === self::TYPE_PREFIX_CONTROLS) {
$row = array_map([self::class, 'prefixControlLiterals'], $row);
$row = array_map(self::prefixControlLiterals(...), $row);
}
fputcsv($resource, $modifier($row), $delim, $quote);
fseek($resource, 0);
$content = stream_get_contents($resource);
return $content;
return stream_get_contents($resource);
}

/**
* Prefixes control literals at the beginning of a cell value with a single quote
* (e.g. `=+value` --> `'=+value`)
*
* @param mixed $cellValue
* @return bool|int|float|string|null
* (e.g. `=+value` --> `'=+value`)
*/
protected static function prefixControlLiterals($cellValue)
protected static function prefixControlLiterals(bool|int|float|string|null $cellValue): bool|int|float|string|null
{
if (!self::shallFilterValue($cellValue)) {
return $cellValue;
Expand All @@ -134,12 +133,10 @@ protected static function prefixControlLiterals($cellValue)

/**
* Removes control literals from the beginning of a cell value
* (e.g. `=+value` --> `value`)
*
* @param mixed $cellValue
* @return bool|int|float|string|null
* (e.g. `=+value` --> `value`)
*/
protected static function removeControlLiterals($cellValue)
protected static function removeControlLiterals(bool|int|float|string|null $cellValue): bool|int|float|string|null
{
if (!self::shallFilterValue($cellValue)) {
return $cellValue;
Expand All @@ -150,10 +147,8 @@ protected static function removeControlLiterals($cellValue)

/**
* Asserts scalar or null types for given cell value.
*
* @param mixed $cellValue
*/
protected static function assertCellValueType($cellValue): void
protected static function assertCellValueType(mixed $cellValue): void
{
// int, float, string, bool, null
if ($cellValue === null || is_scalar($cellValue)) {
Expand All @@ -166,13 +161,12 @@ protected static function assertCellValueType($cellValue): void
}

/**
* Whether cell value shall be filtered, applies to everything
* that is not or cannot be represented as boolean, integer or float.
* Whether cell value shall be filtered.
*
* @param mixed $cellValue
* @return bool
* This applies to everything that is not or cannot be represented
* as boolean, integer or float.
*/
protected static function shallFilterValue($cellValue): bool
protected static function shallFilterValue(bool|int|float|string|null $cellValue): bool
{
return $cellValue !== null
&& !is_bool($cellValue)
Expand Down
Expand Up @@ -15,6 +15,7 @@ expectations and existing behavior.

- :php:`\TYPO3\CMS\Core\Utility\ArrayUtility`
- :php:`\TYPO3\CMS\Core\Utility\ClassNamingUtility`
- :php:`\TYPO3\CMS\Core\Utility\CsvUtility`
- :php:`\TYPO3\CMS\Core\Utility\CommandUtility`
- :php:`\TYPO3\CMS\Core\Utility\DebugUtility`
- :php:`\TYPO3\CMS\Core\Utility\DiffUtility`
Expand Down
4 changes: 2 additions & 2 deletions typo3/sysext/core/Tests/Unit/Utility/CsvUtilityTest.php
Expand Up @@ -92,7 +92,7 @@ public function csvToArrayDataProvider(): array
* @dataProvider csvToArrayDataProvider
* @test
*/
public function csvToArraySplitsAsExpected($input, $fieldDelimiter, $fieldEnclosure, $maximumColumns, $expectedResult): void
public function csvToArraySplitsAsExpected(string $input, string $fieldDelimiter, string $fieldEnclosure, int $maximumColumns, array $expectedResult): void
{
self::assertEquals($expectedResult, CsvUtility::csvToArray($input, $fieldDelimiter, $fieldEnclosure, $maximumColumns));
}
Expand Down Expand Up @@ -163,7 +163,7 @@ public function csvValuesDataProvider(): array
* @dataProvider csvValuesDataProvider
* @test
*/
public function csvValuesReturnsExpectedResult($row, $delimiter, $quote, $expectedResult, $flag): void
public function csvValuesReturnsExpectedResult(array $row, string $delimiter, string $quote, string $expectedResult, int $flag): void
{
self::assertEquals($expectedResult, CsvUtility::csvValues($row, $delimiter, $quote, $flag));
}
Expand Down
Expand Up @@ -77,7 +77,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
return $processedData;
}

$originalValue = $cObj->data[$fieldName];
$originalValue = (string)$cObj->data[$fieldName];

// Set the target variable
$targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, $fieldName);
Expand Down
2 changes: 1 addition & 1 deletion typo3/sysext/lowlevel/Classes/Database/QueryGenerator.php
Expand Up @@ -860,7 +860,7 @@ protected function csvValues($row, $delim = ',', $quote = '"', $conf = [], $tabl
$valueArray[$key] = $this->getProcessedValueExtra($table, $key, $val, $conf, ';');
}
}
return CsvUtility::csvValues($valueArray, $delim, $quote);
return CsvUtility::csvValues($valueArray, (string)$delim, (string)$quote);
}

/**
Expand Down
Expand Up @@ -200,8 +200,8 @@ protected function csvDownloadAction(
array $records
): ResponseInterface {
// Fetch csv related format options
$csvDelimiter = $this->getFormatOption($request, 'delimiter');
$csvQuote = $this->getFormatOption($request, 'quote');
$csvDelimiter = (string)$this->getFormatOption($request, 'delimiter');
$csvQuote = (string)$this->getFormatOption($request, 'quote');

// Create result
$result[] = CsvUtility::csvValues($headerRow, $csvDelimiter, $csvQuote);
Expand Down

0 comments on commit 8d2e34b

Please sign in to comment.