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 {