Skip to content
Merged
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
20 changes: 19 additions & 1 deletion lib/Service/ColumnTypes/IColumnTypeBusiness.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface IColumnTypeBusiness {
public function parseValue($value, ?Column $column): string;

/**
* tests if the given string can be parsed to a value of the column type
* tests if the given value can be parsed to a value of the column type
*
* @param mixed $value
* @param Column|null $column
Expand All @@ -42,4 +42,22 @@ public function canBeParsed($value, ?Column $column): bool;
* @param int|null $rowId
*/
public function validateValue(mixed $value, Column $column, string $userId, int $tableId, ?int $rowId): void;

/**
* tests if the given string can be parsed to a value/id of the column type
*
* @param mixed $value
* @param Column|null $column
* @return bool
*/
public function canBeParsedDisplayValue($value, ?Column $column): bool;

/**
* parses the given string to a value/id of the column type
*
* @param mixed $value
* @param Column|null $column
* @return string
*/
public function parseDisplayValue($value, ?Column $column): string;
}
68 changes: 45 additions & 23 deletions lib/Service/ColumnTypes/SelectionBusiness.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,28 @@ public function parseValue($value, ?Column $column = null): string {
}

$intValue = (int)$value;
if ((string)$intValue === (string)$value) {
// if it seems to be an option ID
foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['id'] === $intValue && $option['label'] !== $value) {
return json_encode($option['id']);
}
if (!is_numeric($value) || $intValue != $value) {
return '';
}

foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['id'] === $intValue) {
return json_encode($option['id']);
}
} else {
foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['label'] === $value) {
return json_encode($option['id']);
}
}

return '';
}

public function parseDisplayValue($value, ?Column $column = null): string {
if (!$column) {
$this->logger->warning('No column given, but expected on ' . __FUNCTION__ . ' within ' . __CLASS__, ['exception' => new \Exception()]);
return '';
}

foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['label'] === $value) {
return json_encode($option['id']);
}
}

Expand All @@ -56,22 +66,34 @@ public function canBeParsed($value, ?Column $column = null): bool {
}

$intValue = (int)$value;
if ((string)$intValue === (string)$value) {
// if it seems to be an option ID
foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['id'] === $intValue && $option['label'] !== $value) {
return true;
}
}
} else {
foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['label'] === $value) {
return true;
}
if (!is_numeric($value) || $intValue != $value) {
return false;
}

foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['id'] === $intValue) {
return true;
}
}

return false;
}

public function canBeParsedDisplayValue($value, ?Column $column = null): bool {
if (!$column) {
$this->logger->warning('No column given, but expected on ' . __FUNCTION__ . ' within ' . __CLASS__, ['exception' => new \Exception()]);
return false;
}
if ($value === null) {
return true;
}

foreach ($column->getSelectionOptionsArray() as $option) {
if ($option['label'] === $value) {
return true;
}
}

return false;
}
}
8 changes: 8 additions & 0 deletions lib/Service/ColumnTypes/SuperBusiness.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public function parseValue($value, ?Column $column = null): string {
return json_encode($value);
}

public function parseDisplayValue($value, ?Column $column = null): string {
return $this->parseValue($value, $column);
}

/**
* @param mixed $value
* @param Column|null $column
Expand All @@ -41,6 +45,10 @@ public function validateValue(mixed $value, Column $column, string $userId, int
// override this method in the child class when needed
}

public function canBeParsedDisplayValue($value, ?Column $column = null): bool {
return $this->canBeParsed($value, $column);
}

protected function isValidDate(string $dateString, string $format): bool {
try {
$dateTime = new DateTime($dateString);
Expand Down
4 changes: 2 additions & 2 deletions lib/Service/ImportService.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,12 @@ private function parseValueByColumnType(string $value, Column $column): string {
$businessClassName .= ucfirst($column->getType()) . ucfirst($column->getSubtype()) . 'Business';
/** @var IColumnTypeBusiness $columnBusiness */
$columnBusiness = Server::get($businessClassName);
if (!$columnBusiness->canBeParsed($value, $column)) {
if (!$columnBusiness->canBeParsedDisplayValue($value, $column)) {
$this->logger->warning('Value ' . $value . ' could not be parsed for column ' . $column->getTitle());
$this->countParsingErrors++;
return '';
}
return $columnBusiness->parseValue($value, $column);
return $columnBusiness->parseDisplayValue($value, $column);
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
$this->logger->debug('Column type business class not found', ['exception' => $e]);
}
Expand Down
135 changes: 135 additions & 0 deletions tests/unit/Service/ColumnTypes/SelectionBusinessTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Tables\Service\ColumnTypes;

use OCA\Tables\Db\Column;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class SelectionBusinessTest extends TestCase {

private SelectionBusiness $selectionBusiness;
private LoggerInterface $logger;
private Column $column;

public function setUp(): void {
$this->logger = $this->createMock(LoggerInterface::class);
$this->selectionBusiness = new SelectionBusiness($this->logger);

$this->column = $this->createMock(Column::class);
$this->column->method('getSelectionOptionsArray')
->willReturn([
['id' => 1, 'label' => 'Option 1'],
['id' => 2, 'label' => 'Option 2'],
['id' => 3, 'label' => 'Option 3'],
['id' => 4, 'label' => '1'],
]);
}

public function parseValueProvider(): array {
return [
'valid integer value' => [2, '2'],
'valid string value' => ['2', '2'],
'valid string value for numeric option' => ['4', '4'],
'invalid value' => [5, ''],
'null value' => [null, ''],
'empty string' => ['', ''],
'float value' => [1.5, ''],
'boolean value' => [true, ''],
'array value' => [[1], ''],
];
}

/**
* @dataProvider parseValueProvider
*/
public function testParseValue($value, string $expected): void {
$result = $this->selectionBusiness->parseValue($value, $this->column);
$this->assertEquals($expected, $result);
}

public function parseDisplayValueProvider(): array {
return [
'valid label' => ['Option 2', '2'],
'invalid label' => ['Invalid Option', ''],
'valid label for numeric option' => ['1', '4'],
'null value' => [null, ''],
'empty string' => ['', ''],
'boolean value' => [true, ''],
'array value' => [[1], ''],
];
}

/**
* @dataProvider parseDisplayValueProvider
*/
public function testParseDisplayValue($value, string $expected): void {
$result = $this->selectionBusiness->parseDisplayValue($value, $this->column);
$this->assertEquals($expected, $result);
}

public function canBeParsedProvider(): array {
return [
'valid integer 1' => [1, true],
'valid string 4' => ['4', true],
'invalid integer' => [5, false],
'invalid integer 0' => [0, false],
'null value' => [null, true],
'empty string' => ['', false],
'float value' => [1.5, false],
'boolean value' => [true, false],
'array value' => [[1], false],
];
}

/**
* @dataProvider canBeParsedProvider
*/
public function testCanBeParsed($value, bool $expected): void {
$result = $this->selectionBusiness->canBeParsed($value, $this->column);
$this->assertEquals($expected, $result);
}

public function canBeParsedDisplayValueProvider(): array {
return [
'valid label' => ['Option 2', true],
'invalid label' => ['Invalid Option', false],
'valid label for numeric option' => ['1', true],
'null value' => [null, true],
'empty string' => ['', false],
'boolean value' => [true, false],
'array value' => [[1], false],
];
}

/**
* @dataProvider canBeParsedDisplayValueProvider
*/
public function testCanBeParsedDisplayValue($value, bool $expected): void {
$result = $this->selectionBusiness->canBeParsedDisplayValue($value, $this->column);
$this->assertEquals($expected, $result);
}

public function withoutColumnProvider(): array {
return [
'parseValue' => ['parseValue', 1, ''],
'parseDisplayValue' => ['parseDisplayValue', 'Option 1', ''],
'canBeParsed' => ['canBeParsed', 1, false],
'canBeParsedDisplayValue' => ['canBeParsedDisplayValue', 'Option 1', false],
];
}

/**
* @dataProvider withoutColumnProvider
*/
public function testMethodsWithoutColumn(string $method, $value, $expected): void {
$result = $this->selectionBusiness->$method($value, null);
$this->assertEquals($expected, $result);
}

}
Loading