Commit 8d2e34ba authored by crell's avatar crell Committed by Stefan Bürk
Browse files

[!!!][TASK] Add native types to CsvUtility

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's avatarNikita Hovratov <nikita.h@live.de>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Reviewed-by: Nikita Hovratov's avatarNikita Hovratov <nikita.h@live.de>
Reviewed-by: Oliver Klee's avatarOliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
parent ffc5261b
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
......@@ -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;
......@@ -97,33 +99,30 @@ class CsvUtility
* @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;
......@@ -134,12 +133,10 @@ class CsvUtility
/**
* 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;
......@@ -150,10 +147,8 @@ class CsvUtility
/**
* 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)) {
......@@ -166,13 +161,12 @@ class CsvUtility
}
/**
* 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)
......
......@@ -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`
......
......@@ -92,7 +92,7 @@ class CsvUtilityTest extends UnitTestCase
* @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));
}
......@@ -163,7 +163,7 @@ class CsvUtilityTest extends UnitTestCase
* @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));
}
......
......@@ -77,7 +77,7 @@ class CommaSeparatedValueProcessor implements DataProcessorInterface
return $processedData;
}
$originalValue = $cObj->data[$fieldName];
$originalValue = (string)$cObj->data[$fieldName];
// Set the target variable
$targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, $fieldName);
......
......@@ -860,7 +860,7 @@ class QueryGenerator
$valueArray[$key] = $this->getProcessedValueExtra($table, $key, $val, $conf, ';');
}
}
return CsvUtility::csvValues($valueArray, $delim, $quote);
return CsvUtility::csvValues($valueArray, (string)$delim, (string)$quote);
}
/**
......
......@@ -200,8 +200,8 @@ class RecordDownloadController
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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment