diff --git a/.scoper-production-dependencies b/.scoper-production-dependencies
index e29620a89e..336650b97b 100644
--- a/.scoper-production-dependencies
+++ b/.scoper-production-dependencies
@@ -7,3 +7,5 @@ psr/http-client
psr/http-factory
psr/http-message
psr/simple-cache
+symfony/uid
+symfony/polyfill-uuid
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 4f05ced258..94e609d38b 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -26,7 +26,7 @@ Share your tables and views with users and groups within your cloud.
Have a good time and manage whatever you want.
]]>
- 2.2.0
+ 2.2.1-dev.0
AGPL-3.0-or-later
Nextcloud GmbH and Nextcloud contributors
Tables
diff --git a/composer.json b/composer.json
index e79266588d..e7566fcfc4 100644
--- a/composer.json
+++ b/composer.json
@@ -66,6 +66,7 @@
"require": {
"phpoffice/phpspreadsheet": "^5.1",
"ext-json": "*",
- "bamarni/composer-bin-plugin": "^1.9.1"
+ "bamarni/composer-bin-plugin": "^1.9.1",
+ "symfony/uid": "^6.4"
}
}
diff --git a/composer.lock b/composer.lock
index 9bef24e1ed..1dd11e0a8b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "22888eddc0a1d9e115a52e0366dd5401",
+ "content-hash": "a23ff2aecc750aa400068e3f79dc35b8",
"packages": [
{
"name": "bamarni/composer-bin-plugin",
@@ -642,6 +642,167 @@
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
},
"time": "2021-10-29T13:26:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-uuid",
+ "version": "v1.37.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-uuid.git",
+ "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/26dfec253c4cf3e51b541b52ddf7e42cb0908e94",
+ "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-uuid": "*"
+ },
+ "suggest": {
+ "ext-uuid": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Uuid\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Grégoire Pineau",
+ "email": "lyrixx@lyrixx.info"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for uuid functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "uuid"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-uuid/tree/v1.37.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-04-10T16:19:22+00:00"
+ },
+ {
+ "name": "symfony/uid",
+ "version": "v6.4.32",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/uid.git",
+ "reference": "6b973c385f00341b246f697d82dc01a09107acdd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/uid/zipball/6b973c385f00341b246f697d82dc01a09107acdd",
+ "reference": "6b973c385f00341b246f697d82dc01a09107acdd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-uuid": "^1.15"
+ },
+ "require-dev": {
+ "symfony/console": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Uid\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Grégoire Pineau",
+ "email": "lyrixx@lyrixx.info"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an object-oriented API to generate and represent UIDs",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "UID",
+ "ulid",
+ "uuid"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/uid/tree/v6.4.32"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-12-23T15:07:59+00:00"
}
],
"packages-dev": [
diff --git a/lib/Analytics/AnalyticsDatasource.php b/lib/Analytics/AnalyticsDatasource.php
index 5a61416fd0..80081b5ade 100644
--- a/lib/Analytics/AnalyticsDatasource.php
+++ b/lib/Analytics/AnalyticsDatasource.php
@@ -231,9 +231,9 @@ private function getData(int $nodeId, ?int $limit, ?int $offset, ?string $nodeTy
if ($datum['columnId'] === $column->getId()) {
// if column type selection, the corresponding labels need to be fetched
if ($column->getType() === 'selection') {
- foreach ($column->getSelectionOptionsArray() as $option) {
- if ($option['id'] === $datum['value']) {
- $value = $option['label'];
+ foreach ($column->getSelectionOptionsCollection() as $option) {
+ if ($option->key() === $datum['value']) {
+ $value = $option->label();
}
}
} else {
diff --git a/lib/Controller/Api1Controller.php b/lib/Controller/Api1Controller.php
index c7fc1c9375..bfb7410a23 100644
--- a/lib/Controller/Api1Controller.php
+++ b/lib/Controller/Api1Controller.php
@@ -21,6 +21,7 @@
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Errors\PermissionError;
use OCA\Tables\Middleware\Attribute\RequirePermission;
+use OCA\Tables\Model\SelectionOptions;
use OCA\Tables\Model\ViewUpdateInput;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ColumnService;
diff --git a/lib/Db/Column.php b/lib/Db/Column.php
index 5f7518d4c9..295cc5b973 100644
--- a/lib/Db/Column.php
+++ b/lib/Db/Column.php
@@ -10,8 +10,10 @@
use JsonSerializable;
use OCA\Tables\Constants\ColumnType;
use OCA\Tables\Dto\Column as ColumnDto;
+use OCA\Tables\Model\SelectionOptions;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ValueObject\ViewColumnInformation;
+use OCA\Tables\Vendor\Symfony\Component\Uid\Uuid;
use ValueError;
/**
@@ -19,6 +21,8 @@
*
* @psalm-import-type TablesColumn from ResponseDefinitions
*
+ * @method string|null getUuid()
+ * @method setUuid(?string $uuid)
* @method getTitle(): string
* @method setTitle(string $title)
* @method getTableId(): int
@@ -58,14 +62,12 @@
* @method setTextDefault(?string $textDefault)
* @method getTextAllowedPattern(): string
* @method setTextAllowedPattern(?string $textAllowedPattern)
- * @method getTextAllowedPattern(): ?string
* @method getTextMaxLength(): int
* @method setTextMaxLength(?int $textMaxLength)
* @method getTextUnique(): bool
* @method setTextUnique(?bool $textUnique)
- * @method getSelectionOptions(): string
- * @method getSelectionDefault(): string
- * @method setSelectionOptions(?string $selectionOptionsArray)
+ * @method string getSelectionOptions()
+ * @method setSelectionOptions(?string $selectionOptions)
* @method setSelectionDefault(?string $selectionDefault)
* @method getSelectionDefault(): ?string
* @method getDatetimeDefault(): string
@@ -113,6 +115,7 @@ class Column extends EntitySuper implements JsonSerializable {
public const META_ID_TITLE = 'id';
+ protected ?string $uuid = null;
protected ?string $title = null;
protected ?int $tableId = null;
protected ?string $createdBy = null;
@@ -164,6 +167,7 @@ class Column extends EntitySuper implements JsonSerializable {
public function __construct() {
$this->addType('id', 'integer');
+ $this->addType('uuid', 'string');
$this->addType('tableId', 'integer');
$this->addType('mandatory', 'boolean');
@@ -185,6 +189,8 @@ public function __construct() {
$this->addType('showUserStatus', 'boolean');
$this->addType('customSettings', 'string');
+
+ $this->addType('selectionOptions', 'string');
}
public static function isValidMetaTypeId(int $metaTypeId): bool {
@@ -197,8 +203,41 @@ public static function isValidMetaTypeId(int $metaTypeId): bool {
], true);
}
+ public function setter (string $name, array $args): void {
+ if ($name === 'uuid') {
+ $this->setOrAssignUuid((string)$args[0]);
+ return;
+ }
+
+ parent::setter($name, $args);
+ }
+
+ private function assignUuid(): void {
+ if ($this->uuid !== null) {
+ throw new \RuntimeException('This column already has a UUID, they are immutable');
+ }
+ $this->applyUuid(Uuid::v7()->toRfc4122());
+ }
+
+ private function setOrAssignUuid(?string $uuid): void {
+ if ($this->uuid !== null) {
+ throw new \RuntimeException('This column already has a UUID, they are immutable');
+ }
+ if ($uuid === null) {
+ $this->assignUuid();
+ return;
+ }
+ $this->applyUuid($uuid);
+ }
+
+ private function applyUuid(string $uuid): void {
+ $this->uuid = $uuid;
+ $this->markFieldUpdated('uuid');
+ }
+
public static function fromDto(ColumnDto $data): self {
$column = new self();
+ $column->assignUuid();
$column->setTitle($data->getTitle());
$column->setType($data->getType());
$column->setSubtype($data->getSubtype() ?? '');
@@ -214,8 +253,7 @@ public static function fromDto(ColumnDto $data): self {
$column->setNumberDecimals($data->getNumberDecimals());
$column->setNumberPrefix($data->getNumberPrefix() ?? '');
$column->setNumberSuffix($data->getNumberSuffix() ?? '');
- $column->setSelectionOptions($data->getSelectionOptions());
- $column->setSelectionDefault($data->getSelectionDefault());
+ $column->setSelectionOptionsCollection(SelectionOptions::createFromInputJsonString($data->getSelectionOptions() ?? '[]', $data->getSelectionDefault()));
$column->setDatetimeDefault($data->getDatetimeDefault());
$column->setUsergroupDefault($data->getUsergroupDefault());
$column->setUsergroupMultipleItems($data->getUsergroupMultipleItems());
@@ -241,18 +279,17 @@ public function setUsergroupDefaultArray(array $array):void {
$this->setUsergroup($json);
}
- public function getSelectionOptionsArray(): array {
- $options = $this->getSelectionOptions();
- if ($options !== '' && $options !== null && $options !== 'null') {
- return \json_decode($options, true);
- } else {
- return [];
- }
+ public function getSelectionOptionsCollection(): SelectionOptions {
+ return SelectionOptions::createFromInputJsonString($this->getSelectionOptions() ?? '[]', $this->getSelectionDefault());
}
- public function setSelectionOptionsArray(array $array):void {
- $json = \json_encode($array);
- $this->setSelectionOptions($json);
+ public function setSelectionOptionsCollection(SelectionOptions $selectionOptions): void {
+ $this->setSelectionOptions(json_encode($selectionOptions->jsonSerialize()));
+ $this->setSelectionDefault($selectionOptions->defaultSerialized());
+ }
+
+ public function getSelectionOptionsArray(): ?array {
+ return $this->getSelectionOptionsCollection()->jsonSerialize();
}
/**
@@ -261,6 +298,7 @@ public function setSelectionOptionsArray(array $array):void {
public function jsonSerialize(): array {
return [
'id' => $this->id,
+ 'uuid' => $this->uuid,
'tableId' => $this->tableId,
'title' => $this->title,
'createdBy' => $this->createdBy,
diff --git a/lib/Migration/Version2020Date20260513185340.php b/lib/Migration/Version2020Date20260513185340.php
new file mode 100644
index 0000000000..32766789b2
--- /dev/null
+++ b/lib/Migration/Version2020Date20260513185340.php
@@ -0,0 +1,96 @@
+hasTable(self::TARGET_TABLE)) {
+ return null;
+ }
+
+ $columnsTable = $schema->getTable(self::TARGET_TABLE);
+ if (!$columnsTable->hasColumn(self::COL_UUID)) {
+ $columnsTable->addColumn(self::COL_UUID, Types::STRING, [
+ 'notnull' => false,
+ 'default' => null,
+ 'length' => 36,
+ 'comment' => 'UUIDv7 identifier to support structural updates across instances',
+ ]);
+ }
+
+ return $schema;
+ }
+
+ #[Override]
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+
+ $qbUpdate = $this->db->getQueryBuilder();
+ $qbUpdate->update(self::TARGET_TABLE)
+ ->set(self::COL_UUID, $qbUpdate->createParameter('columnUuid'))
+ ->where($qbUpdate->expr()->eq(self::COL_ID, $qbUpdate->createParameter('columnLocalId')));
+
+ $qbSelect = $this->db->getQueryBuilder();
+ $qbSelect->select(self::COL_ID)
+ ->from(self::TARGET_TABLE);
+ $select = $qbSelect->executeQuery();
+
+ $writeBatches = 250;
+ $updates = 0;
+
+ try {
+ $this->db->beginTransaction();
+ while (($columnId = $select->fetchOne()) !== false) {
+ $qbUpdate->setParameters(
+ [
+ 'columnLocalId' => (int)$columnId,
+ 'columnUuid' => Uuid::v7()->toRfc4122(),
+ ],
+ [
+ Types::INTEGER,
+ Types::STRING,
+ ]
+ );
+ $qbUpdate->executeStatement();
+ $updates++;
+ if ($updates % $writeBatches === 0) {
+ $this->db->commit();
+ $this->db->beginTransaction();
+ }
+ }
+ $this->db->commit();
+ } catch (\Exception $e) {
+ $this->db->rollBack();
+ throw $e;
+ }
+
+ $select->closeCursor();
+ }
+}
diff --git a/lib/Model/SelectionOption.php b/lib/Model/SelectionOption.php
new file mode 100644
index 0000000000..d85aa94420
--- /dev/null
+++ b/lib/Model/SelectionOption.php
@@ -0,0 +1,51 @@
+key;
+ }
+
+ public function label(): string {
+ return $this->label;
+ }
+
+ #[\Override]
+ public function jsonSerialize(): array {
+ return [
+ 'id' => $this->key,
+ 'label' => $this->label,
+ ];
+ }
+}
diff --git a/lib/Model/SelectionOptions.php b/lib/Model/SelectionOptions.php
new file mode 100644
index 0000000000..4a860d11b9
--- /dev/null
+++ b/lib/Model/SelectionOptions.php
@@ -0,0 +1,132 @@
+selectionOptions !== null) {
+ // `check` subtype has options set to null
+ foreach ($this->selectionOptions as $selectionOption) {
+ if (!$selectionOption instanceof SelectionOption) {
+ throw new \InvalidArgumentException('Provided selectionOption must be an instance of SelectionOption');
+ }
+ }
+ }
+ if (is_int($this->default)) {
+ $this->applyIntDefault();
+ } else if (is_string($this->default)) {
+ $this->applyStringDefault();
+ }
+ }
+
+ private function applyIntDefault(): void {
+ // default value targets a specific key
+ foreach ($this->selectionOptions as $selectionOption) {
+ if ($selectionOption->key() === $this->default) {
+ return;
+ }
+ }
+ // if the default is not available anymore, we pragmatically unset it.
+ $this->default = null;
+ }
+
+ private function applyStringDefault(): void {
+ // default value is a JSON string targeting multiple keys
+
+ $workDefault = \json_decode($this->default(), true);
+ if (!is_array($workDefault)) {
+ $this->default = null;
+ return;
+ }
+
+ $confirmedOptions = [];
+ foreach ($workDefault as $defaultOption) {
+ $normalizedDefaultOption = (int)$defaultOption;
+ foreach ($this->selectionOptions as $selectionOption) {
+ if ($selectionOption->key() === $normalizedDefaultOption) {
+ $confirmedOptions[] = $normalizedDefaultOption;
+ continue 2;
+ }
+ // if the default is not available anymore, we pragmatically ignore it.
+ }
+ }
+ $this->default = $confirmedOptions;
+ }
+
+ public static function createFromInputArray(?array $data, null|bool|int|string $default): self {
+ if ($data !== null) {
+ $selectionOptions = [];
+ foreach ($data as $inputSelectionOption) {
+ $selectionOptions[] = SelectionOption::createFromInputArray($inputSelectionOption);
+ }
+ }
+ // `check` subtype has null as options
+ return new self($selectionOptions ?? null, $default);
+ }
+
+ public static function createFromInputJsonString(?string $data, null|bool|int|string $default): self {
+ if ($data !== null && $data !== 'null') {
+ $inputArray = \json_decode($data === '' ? '[]' : $data, true);
+ if (!is_array($inputArray)) {
+ throw new \InvalidArgumentException('Provided selectionOption is not a valid JSON string');
+ }
+ } else {
+ // `check` subtype has "null" as options
+ $inputArray = null;
+ }
+ return self::createFromInputArray($inputArray, $default);
+ }
+
+ public function default(): mixed {
+ return $this->default;
+ }
+
+ public function defaultSerialized(): string {
+ return \json_encode($this->default());
+ }
+
+ #[\Override]
+ public function jsonSerialize(): ?array {
+ if ($this->selectionOptions === null) {
+ return null;
+ }
+ return array_map(static fn (SelectionOption $so) => $so->jsonSerialize(), $this->selectionOptions);
+ }
+
+ #[\Override]
+ public function current(): SelectionOption {
+ return current($this->selectionOptions);
+ }
+
+ #[\Override]
+ public function next(): void {
+ next($this->selectionOptions);
+ }
+
+ #[\Override]
+ public function key(): ?int {
+ return key($this->selectionOptions);
+ }
+
+ #[\Override]
+ public function valid(): bool {
+ return $this->key() !== null;
+ }
+
+ #[\Override]
+ public function rewind(): void {
+ reset($this->selectionOptions);
+ }
+}
diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php
index 1dd4d5f6a8..c006a46ccb 100644
--- a/lib/ResponseDefinitions.php
+++ b/lib/ResponseDefinitions.php
@@ -117,6 +117,7 @@
*
* @psalm-type TablesColumn = array{
* id: int,
+ * uuid: string,
* title: string,
* tableId: int,
* createdBy: string,
diff --git a/lib/Service/ColumnService.php b/lib/Service/ColumnService.php
index 1f7322e8f1..2d02a7931e 100644
--- a/lib/Service/ColumnService.php
+++ b/lib/Service/ColumnService.php
@@ -21,14 +21,17 @@
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Errors\PermissionError;
use OCA\Tables\Helper\UserHelper;
+use OCA\Tables\Model\SelectionOptions;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ValueObject\Title;
use OCA\Tables\Service\ValueObject\ViewColumnInformation;
use OCA\Tables\Validation\ColumnDtoValidator;
+use OCA\Tables\Vendor\Symfony\Component\Uid\Uuid;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\IL10N;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Uid\NilUlid;
/**
* @psalm-import-type TablesColumn from ResponseDefinitions
@@ -74,6 +77,7 @@ public function __construct(
}
/**
+ * @return Column[]
* @throws InternalError
* @throws PermissionError
*/
@@ -141,7 +145,7 @@ public function findAllByManagedView(View $view, string $userId): array {
/**
* @param int $viewId
* @param string|null $userId
- * @return array
+ * @return Column[]
* @throws NotFoundError
* @throws PermissionError
* @throws InternalError
@@ -391,11 +395,10 @@ public function update(
$item->setNumberMin($columnDto->getNumberMin());
$item->setNumberMax($columnDto->getNumberMax());
$item->setNumberDecimals($columnDto->getNumberDecimals());
- if ($columnDto->getSelectionOptions() !== null) {
- $item->setSelectionOptions($columnDto->getSelectionOptions());
- }
- if ($columnDto->getSelectionDefault() !== null) {
- $item->setSelectionDefault($columnDto->getSelectionDefault());
+ if ($columnDto->getSelectionOptions() !== null || $columnDto->getSelectionDefault() !== null) {
+ $item->setSelectionOptionsCollection(SelectionOptions::createFromInputJsonString(
+ $columnDto->getSelectionOptions(), $columnDto->getSelectionDefault())
+ );
}
$item->setDatetimeDefault($columnDto->getDatetimeDefault());
@@ -672,6 +675,15 @@ private function enhanceColumns(?array $columns, ?View $view = null): array {
*/
public function importColumn(Table $table, array $column): int {
$item = new Column();
+ if (isset($column['uuid'])) {
+ $uuid = (string)$column['uuid'];
+ if ($uuid === '') {
+ $uuid = null;
+ } elseif (!Uuid::isValid($uuid)) {
+ throw new \InvalidArgumentException('Invalid UUID provided');
+ }
+ }
+ $item->setUuid($uuid ?? null);
$item->setTableId($table->getId());
$item->setTitle($column['title']);
$item->setCreatedBy($table->getOwnership());
@@ -692,8 +704,7 @@ public function importColumn(Table $table, array $column): int {
$item->setTextAllowedPattern($column['textAllowedPattern']);
$item->setTextMaxLength($column['textMaxLength']);
$item->setTextUnique($column['textUnique']);
- $item->setSelectionOptions(json_encode($column['selectionOptions']));
- $item->setSelectionDefault($column['selectionDefault']);
+ $item->setSelectionOptionsCollection(SelectionOptions::createFromInputArray($column['selectionOptions'], $column['selectionDefault']));
$item->setDatetimeDefault($column['datetimeDefault']);
$item->setUsergroupDefault(json_encode($column['usergroupDefault']));
$item->setUsergroupMultipleItems($column['usergroupMultipleItems']);
diff --git a/lib/Service/ColumnTypes/SelectionBusiness.php b/lib/Service/ColumnTypes/SelectionBusiness.php
index 3fd6f19c76..423478d6ec 100644
--- a/lib/Service/ColumnTypes/SelectionBusiness.php
+++ b/lib/Service/ColumnTypes/SelectionBusiness.php
@@ -22,9 +22,9 @@ public function parseValue($value, Column $column): string {
return '';
}
- foreach ($column->getSelectionOptionsArray() as $option) {
- if ($option['id'] === $intValue) {
- return json_encode((string)$option['id']);
+ foreach ($column->getSelectionOptionsCollection() as $option) {
+ if ($option->key() === $intValue) {
+ return json_encode((string)$option->key());
}
}
@@ -32,9 +32,9 @@ public function parseValue($value, Column $column): string {
}
public function parseDisplayValue($value, Column $column): string {
- foreach ($column->getSelectionOptionsArray() as $option) {
- if ($option['label'] === $value) {
- return json_encode($option['id']);
+ foreach ($column->getSelectionOptionsCollection() as $option) {
+ if ($option->label() === $value) {
+ return json_encode($option->key());
}
}
@@ -46,7 +46,7 @@ public function parseDisplayValue($value, Column $column): string {
* @param Column $column
* @return bool
*/
- public function canBeParsed($value, Column $column): bool {
+ public function canBeParsed(mixed $value, Column $column): bool {
if ($value === null) {
return true;
}
@@ -56,8 +56,8 @@ public function canBeParsed($value, Column $column): bool {
return false;
}
- foreach ($column->getSelectionOptionsArray() as $option) {
- if ($option['id'] === $intValue) {
+ foreach ($column->getSelectionOptionsCollection() as $option) {
+ if ($option->key() === $intValue) {
return true;
}
}
@@ -70,8 +70,8 @@ public function canBeParsedDisplayValue($value, Column $column): bool {
return true;
}
- foreach ($column->getSelectionOptionsArray() as $option) {
- if ($option['label'] === $value) {
+ foreach ($column->getSelectionOptionsCollection() as $option) {
+ if ($option->label() === $value) {
return true;
}
}
diff --git a/lib/Service/ColumnTypes/SelectionMultiBusiness.php b/lib/Service/ColumnTypes/SelectionMultiBusiness.php
index b8799a6613..629a9808f4 100644
--- a/lib/Service/ColumnTypes/SelectionMultiBusiness.php
+++ b/lib/Service/ColumnTypes/SelectionMultiBusiness.php
@@ -8,10 +8,11 @@
namespace OCA\Tables\Service\ColumnTypes;
use OCA\Tables\Db\Column;
+use OCA\Tables\Model\SelectionOptions;
class SelectionMultiBusiness extends SuperBusiness {
- private array $options = [];
+ private SelectionOptions $options;
/**
* @param mixed $value (array|string|null)
@@ -23,7 +24,7 @@ public function parseValue($value, Column $column): string {
return json_encode([]);
}
- $this->options = $column->getSelectionOptionsArray();
+ $this->options = $column->getSelectionOptionsCollection();
$wasString = false;
if (is_string($value)) {
@@ -48,20 +49,18 @@ public function parseValue($value, Column $column): string {
* @param int|string|null $value int assume as option ID, string assumes a label
* @return int|null return always the option ID or null
*/
- private function getOptionIdForValue($value): ?int {
- if ($value === null) {
+ private function getOptionIdForValue(mixed $value): ?int {
+ if ($value === null || !isset($this->options)) {
return null;
}
foreach ($this->options as $option) {
if (is_int($value)) {
- if ($option['id'] === $value) {
- return $option['id'];
- }
- } else {
- if ($option['label'] === $value) {
- return $option['id'];
+ if ($option->key() === $value) {
+ return $option->key();
}
+ } else if ($option->label() === $value) {
+ return $option->key();
}
}
return null;
@@ -77,7 +76,7 @@ public function canBeParsed($value, Column $column): bool {
return true;
}
- $this->options = $column->getSelectionOptionsArray();
+ $this->options = $column->getSelectionOptionsCollection();
$wasString = false;
if (is_string($value)) {