diff --git a/composer.json b/composer.json index 5d22e69d..6b67a24d 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "phpcs": "./vendor/bin/phpcs --standard=phpcs.xml", "phpcs:fix": "./vendor/bin/phpcbf --standard=phpcs.xml", "phpcs:output": "./vendor/bin/phpcs --standard=phpcs.xml --report=json lib/ 2>/dev/null | tail -1 > phpcs-output.json", - "phpmd": "phpmd lib text phpmd.xml || echo 'PHPMD not installed, skipping...'", + "phpmd": "./vendor/bin/phpmd lib text phpmd.xml --exclude '*/Resources/template/*' --baseline-file phpmd.baseline.xml || echo 'PHPMD not installed, skipping...'", "phpmetrics": "./vendor/bin/phpmetrics --report-html=phpmetrics lib/", "psalm": "./vendor/bin/psalm --threads=1 --no-cache || echo 'Psalm not installed, skipping...'", "phpstan": "./vendor/bin/phpstan analyse --memory-limit=1G || echo 'PHPStan not installed, skipping...'", diff --git a/lib/Controller/PreferencesController.php b/lib/Controller/PreferencesController.php index 7675f58b..9e47886c 100644 --- a/lib/Controller/PreferencesController.php +++ b/lib/Controller/PreferencesController.php @@ -116,24 +116,23 @@ public function setPreference(string $key, string $value=''): JSONResponse return new JSONResponse(data: ['message' => 'Invalid key'], statusCode: Http::STATUS_BAD_REQUEST); } - $stored = null; if ($value === '') { $this->config->deleteUserValue( userId: $user->getUID(), appName: Application::APP_ID, key: 'pref_'.$safeKey ); - } else { - $this->config->setUserValue( - userId: $user->getUID(), - appName: Application::APP_ID, - key: 'pref_'.$safeKey, - value: $value - ); - $stored = $value; + return new JSONResponse(data: ['value' => null]); } - return new JSONResponse(data: ['value' => $stored]); + $this->config->setUserValue( + userId: $user->getUID(), + appName: Application::APP_ID, + key: 'pref_'.$safeKey, + value: $value + ); + + return new JSONResponse(data: ['value' => $value]); }//end setPreference() diff --git a/lib/Mcp/Handler/UpsertSchemaHandler.php b/lib/Mcp/Handler/UpsertSchemaHandler.php index e18c7035..b95afe26 100644 --- a/lib/Mcp/Handler/UpsertSchemaHandler.php +++ b/lib/Mcp/Handler/UpsertSchemaHandler.php @@ -77,20 +77,29 @@ public function handle(array $args): array if ($existing !== null) { $schema = $schemaMapper->updateFromArray($existing->getId(), $blob); - $action = 'updated'; - } else { - $schema = $schemaMapper->createFromArray($blob); - $action = 'created'; - $this->attachSchemaToRegister( - registerMapper: $registerMapper, - registerSlug: $registerSlug, - schemaId: $schema->getId() - ); + return [ + 'success' => true, + 'action' => 'updated', + 'schema' => [ + 'id' => $schema->getId(), + 'slug' => $namespacedSlug, + 'shortSlug' => $rawSlug, + 'title' => $title, + 'register' => $registerSlug, + ], + ]; } + $schema = $schemaMapper->createFromArray($blob); + $this->attachSchemaToRegister( + registerMapper: $registerMapper, + registerSlug: $registerSlug, + schemaId: $schema->getId() + ); + return [ 'success' => true, - 'action' => $action, + 'action' => 'created', 'schema' => [ 'id' => $schema->getId(), 'slug' => $namespacedSlug, diff --git a/phpmd.baseline.xml b/phpmd.baseline.xml new file mode 100644 index 00000000..1bff29df --- /dev/null +++ b/phpmd.baseline.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml index 8c46a06a..cd069775 100644 --- a/psalm.xml +++ b/psalm.xml @@ -12,6 +12,18 @@ + + @@ -60,7 +72,18 @@ + + + + @@ -85,6 +108,7 @@ + diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2653f55c..5841ac82 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -28,6 +28,18 @@ }); } +// OpenRegister types are referenced by hard-typed constructor parameters in +// controllers, services, repair steps and listeners. When the real +// OpenRegister sources are not on the autoload path (CI / out-of-container) +// load the minimal stub set so PHPUnit's MockBuilder can resolve the types. +// The stubs are guarded by class_exists() so they are a no-op when the real +// classes ARE available (in-container run). +require_once __DIR__ . '/stubs/openregister-stubs.php'; + +// Same guard for the IMcpToolProvider interface which ships with OR but may +// not be present until OR#1466 merges. +require_once __DIR__ . '/Stubs/Mcp/IMcpToolProvider.php'; + // Bootstrap Nextcloud if available. Inside the docker container we'll get // the full NC runtime; outside (CI / local dev) we fall back to the // vendor/nextcloud/ocp stubs and run only the pure-unit subset. diff --git a/tests/stubs/openregister-stubs.php b/tests/stubs/openregister-stubs.php index 6b319164..39af2331 100644 --- a/tests/stubs/openregister-stubs.php +++ b/tests/stubs/openregister-stubs.php @@ -440,6 +440,33 @@ public function find(int|string $id, ?array $_extend = [], bool $_multitenancy = } } } + + if (class_exists(FileService::class, autoload: false) === false) { + /** + * Stub FileService — `getFile` call surface used by IconService. + * + * The real OR FileService wraps Nextcloud Files and returns an + * OCP\Files\File node. Tests mock `getFile()` to return a mock + * File node or to throw, so only the method signature needs to + * match here. + */ + class FileService + { + /** + * Retrieve a file attached to an object. + * + * @param string $object UUID of the owning object. + * @param string $file File name / path to retrieve. + * + * @return \OCP\Files\File The file node. + */ + public function getFile(string $object, string $file): \OCP\Files\File + { + // Stub — tests mock this method; real implementation is in OR. + throw new \RuntimeException('FileService::getFile stub — must be mocked in tests.'); + } + } + } } namespace OCA\OpenRegister\Event {