1 Commits

Author SHA1 Message Date
Sebastian fae4ee8929 fix(deps): update dependency symfony/console to v8
JS Unit Tests / test (pull_request) Successful in 21s
Build Test / build (pull_request) Successful in 25s
PHP Unit Tests / test (pull_request) Successful in 1m46s
2026-05-17 03:03:00 +00:00
166 changed files with 1346 additions and 1983 deletions
Generated
+17 -27
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "95b9110e6c06e2d30edd0283b1bd630d", "content-hash": "f7fc2a065e49b48ce405b1a490da44af",
"packages": [ "packages": [
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
@@ -393,16 +393,16 @@
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
"version": "3.0.55", "version": "3.0.52",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpseclib/phpseclib.git", "url": "https://github.com/phpseclib/phpseclib.git",
"reference": "db9744e6d47e742b1f974e965ad49bdd041105af" "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db9744e6d47e742b1f974e965ad49bdd041105af", "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2adaefc83df2ec548558307690f376dd7d4f4fce",
"reference": "db9744e6d47e742b1f974e965ad49bdd041105af", "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -483,7 +483,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/phpseclib/phpseclib/issues", "issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.55" "source": "https://github.com/phpseclib/phpseclib/tree/3.0.52"
}, },
"funding": [ "funding": [
{ {
@@ -499,7 +499,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-06-14T23:24:10+00:00" "time": "2026-04-27T07:02:15+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -606,29 +606,23 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v8.1.1", "version": "v8.0.11",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d" "reference": "3156577f46a38aa1b9323aad223de7a9cd426782"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d", "url": "https://api.github.com/repos/symfony/console/zipball/3156577f46a38aa1b9323aad223de7a9cd426782",
"reference": "b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d", "reference": "3156577f46a38aa1b9323aad223de7a9cd426782",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.4.1", "php": ">=8.4",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php85": "^1.32",
"symfony/service-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3",
"symfony/string": "^7.4.6|^8.0.6" "symfony/string": "^7.4|^8.0"
},
"conflict": {
"symfony/dependency-injection": "<8.1",
"symfony/event-dispatcher": "<8.1"
}, },
"provide": { "provide": {
"psr/log-implementation": "1.0|2.0|3.0" "psr/log-implementation": "1.0|2.0|3.0"
@@ -636,18 +630,14 @@
"require-dev": { "require-dev": {
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
"symfony/config": "^7.4|^8.0", "symfony/config": "^7.4|^8.0",
"symfony/dependency-injection": "^8.1", "symfony/dependency-injection": "^7.4|^8.0",
"symfony/event-dispatcher": "^8.1", "symfony/event-dispatcher": "^7.4|^8.0",
"symfony/filesystem": "^7.4|^8.0",
"symfony/http-foundation": "^7.4|^8.0", "symfony/http-foundation": "^7.4|^8.0",
"symfony/http-kernel": "^7.4|^8.0", "symfony/http-kernel": "^7.4|^8.0",
"symfony/lock": "^7.4|^8.0", "symfony/lock": "^7.4|^8.0",
"symfony/messenger": "^7.4|^8.0", "symfony/messenger": "^7.4|^8.0",
"symfony/mime": "^7.4|^8.0",
"symfony/process": "^7.4|^8.0", "symfony/process": "^7.4|^8.0",
"symfony/stopwatch": "^7.4|^8.0", "symfony/stopwatch": "^7.4|^8.0",
"symfony/uid": "^7.4|^8.0",
"symfony/validator": "^7.4|^8.0",
"symfony/var-dumper": "^7.4|^8.0" "symfony/var-dumper": "^7.4|^8.0"
}, },
"type": "library", "type": "library",
@@ -682,7 +672,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v8.1.1" "source": "https://github.com/symfony/console/tree/v8.0.11"
}, },
"funding": [ "funding": [
{ {
@@ -702,7 +692,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-06-16T12:55:20+00:00" "time": "2026-05-13T12:07:53+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
+143 -143
View File
@@ -747,9 +747,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@oxc-project/types": { "node_modules/@oxc-project/types": {
"version": "0.132.0", "version": "0.130.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
"integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/Boshen" "url": "https://github.com/sponsors/Boshen"
@@ -1083,9 +1083,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rolldown/binding-android-arm64": { "node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
"integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1099,9 +1099,9 @@
} }
}, },
"node_modules/@rolldown/binding-darwin-arm64": { "node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
"integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1115,9 +1115,9 @@
} }
}, },
"node_modules/@rolldown/binding-darwin-x64": { "node_modules/@rolldown/binding-darwin-x64": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
"integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1131,9 +1131,9 @@
} }
}, },
"node_modules/@rolldown/binding-freebsd-x64": { "node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
"integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1147,9 +1147,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm-gnueabihf": { "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
"integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1163,9 +1163,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm64-gnu": { "node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
"integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1179,9 +1179,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm64-musl": { "node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
"integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1195,9 +1195,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-ppc64-gnu": { "node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
"integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -1211,9 +1211,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-s390x-gnu": { "node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
"integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -1227,9 +1227,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-x64-gnu": { "node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
"integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1243,9 +1243,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-x64-musl": { "node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
"integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1259,9 +1259,9 @@
} }
}, },
"node_modules/@rolldown/binding-openharmony-arm64": { "node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
"integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1275,9 +1275,9 @@
} }
}, },
"node_modules/@rolldown/binding-wasm32-wasi": { "node_modules/@rolldown/binding-wasm32-wasi": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
"integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
"cpu": [ "cpu": [
"wasm32" "wasm32"
], ],
@@ -1293,9 +1293,9 @@
} }
}, },
"node_modules/@rolldown/binding-win32-arm64-msvc": { "node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
"integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1309,9 +1309,9 @@
} }
}, },
"node_modules/@rolldown/binding-win32-x64-msvc": { "node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
"integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1688,14 +1688,14 @@
} }
}, },
"node_modules/@vitest/coverage-v8": { "node_modules/@vitest/coverage-v8": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz",
"integrity": "sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==", "integrity": "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@bcoe/v8-coverage": "^1.0.2", "@bcoe/v8-coverage": "^1.0.2",
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"ast-v8-to-istanbul": "^1.0.0", "ast-v8-to-istanbul": "^1.0.0",
"istanbul-lib-coverage": "^3.2.2", "istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1", "istanbul-lib-report": "^3.0.1",
@@ -1709,8 +1709,8 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
}, },
"peerDependencies": { "peerDependencies": {
"@vitest/browser": "4.1.7", "@vitest/browser": "4.1.6",
"vitest": "4.1.7" "vitest": "4.1.6"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@vitest/browser": { "@vitest/browser": {
@@ -1719,16 +1719,16 @@
} }
}, },
"node_modules/@vitest/expect": { "node_modules/@vitest/expect": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
"integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@standard-schema/spec": "^1.1.0", "@standard-schema/spec": "^1.1.0",
"@types/chai": "^5.2.2", "@types/chai": "^5.2.2",
"@vitest/spy": "4.1.7", "@vitest/spy": "4.1.6",
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"chai": "^6.2.2", "chai": "^6.2.2",
"tinyrainbow": "^3.1.0" "tinyrainbow": "^3.1.0"
}, },
@@ -1737,13 +1737,13 @@
} }
}, },
"node_modules/@vitest/mocker": { "node_modules/@vitest/mocker": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz",
"integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/spy": "4.1.7", "@vitest/spy": "4.1.6",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"magic-string": "^0.30.21" "magic-string": "^0.30.21"
}, },
@@ -1774,9 +1774,9 @@
} }
}, },
"node_modules/@vitest/pretty-format": { "node_modules/@vitest/pretty-format": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz",
"integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1787,13 +1787,13 @@
} }
}, },
"node_modules/@vitest/runner": { "node_modules/@vitest/runner": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz",
"integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"pathe": "^2.0.3" "pathe": "^2.0.3"
}, },
"funding": { "funding": {
@@ -1801,14 +1801,14 @@
} }
}, },
"node_modules/@vitest/snapshot": { "node_modules/@vitest/snapshot": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz",
"integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/pretty-format": "4.1.7", "@vitest/pretty-format": "4.1.6",
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
"pathe": "^2.0.3" "pathe": "^2.0.3"
}, },
@@ -1817,9 +1817,9 @@
} }
}, },
"node_modules/@vitest/spy": { "node_modules/@vitest/spy": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz",
"integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
@@ -1827,13 +1827,13 @@
} }
}, },
"node_modules/@vitest/ui": { "node_modules/@vitest/ui": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.6.tgz",
"integrity": "sha512-TP6utB2yX6rsJNVRo2qAlsi48i1YwFTrLV2tnTtWqJaYX7m4lRCCLirZBjU6xC5m0RsPHr+L2+N+eIPhgEzFfw==", "integrity": "sha512-wiu5em68DfGv/2HFvI1Njr7JI2CHcBlQvereSzVG8my53PRxjTNOCsD9VOkRKrsJBDHmyuXvosxWZw7T91a2mw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"flatted": "^3.4.2", "flatted": "^3.4.2",
"pathe": "^2.0.3", "pathe": "^2.0.3",
@@ -1845,17 +1845,17 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
}, },
"peerDependencies": { "peerDependencies": {
"vitest": "4.1.7" "vitest": "4.1.6"
} }
}, },
"node_modules/@vitest/utils": { "node_modules/@vitest/utils": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz",
"integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/pretty-format": "4.1.7", "@vitest/pretty-format": "4.1.6",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"tinyrainbow": "^3.1.0" "tinyrainbow": "^3.1.0"
}, },
@@ -2084,9 +2084,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vue/test-utils": { "node_modules/@vue/test-utils": {
"version": "2.4.11", "version": "2.4.10",
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.11.tgz", "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.10.tgz",
"integrity": "sha512-GDqaqZsA6m2E5vNzej0aYiIb6BX8xV9pNSbbbXKOfEYwg7ZNblVX8suyqmUBThq8VIrgAJNxn+z72hVtUeiWHA==", "integrity": "sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2944,9 +2944,9 @@
} }
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.4.11", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.3.tgz",
"integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", "integrity": "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==",
"license": "(MPL-2.0 OR Apache-2.0)", "license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": { "optionalDependencies": {
"@types/trusted-types": "^2.0.7" "@types/trusted-types": "^2.0.7"
@@ -3206,9 +3206,9 @@
} }
}, },
"node_modules/eslint-plugin-vue": { "node_modules/eslint-plugin-vue": {
"version": "10.9.2", "version": "10.9.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.2.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.1.tgz",
"integrity": "sha512-4g7ZP3pYcuqd7Zp0pzUKcos0W+RkjBz4EGdhJ92FcYk6v03Ti/GK5NwjgsjxHK+98eXDbHeK7VtX1az7/8doZA==", "integrity": "sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -4900,9 +4900,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.15", "version": "8.5.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -4919,7 +4919,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.12", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
@@ -4951,9 +4951,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.8.4", "version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -5076,12 +5076,12 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/rolldown": { "node_modules/rolldown": {
"version": "1.0.2", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
"integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@oxc-project/types": "=0.132.0", "@oxc-project/types": "=0.130.0",
"@rolldown/pluginutils": "^1.0.0" "@rolldown/pluginutils": "^1.0.0"
}, },
"bin": { "bin": {
@@ -5091,21 +5091,21 @@
"node": "^20.19.0 || >=22.12.0" "node": "^20.19.0 || >=22.12.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rolldown/binding-android-arm64": "1.0.2", "@rolldown/binding-android-arm64": "1.0.1",
"@rolldown/binding-darwin-arm64": "1.0.2", "@rolldown/binding-darwin-arm64": "1.0.1",
"@rolldown/binding-darwin-x64": "1.0.2", "@rolldown/binding-darwin-x64": "1.0.1",
"@rolldown/binding-freebsd-x64": "1.0.2", "@rolldown/binding-freebsd-x64": "1.0.1",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.2", "@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
"@rolldown/binding-linux-arm64-gnu": "1.0.2", "@rolldown/binding-linux-arm64-gnu": "1.0.1",
"@rolldown/binding-linux-arm64-musl": "1.0.2", "@rolldown/binding-linux-arm64-musl": "1.0.1",
"@rolldown/binding-linux-ppc64-gnu": "1.0.2", "@rolldown/binding-linux-ppc64-gnu": "1.0.1",
"@rolldown/binding-linux-s390x-gnu": "1.0.2", "@rolldown/binding-linux-s390x-gnu": "1.0.1",
"@rolldown/binding-linux-x64-gnu": "1.0.2", "@rolldown/binding-linux-x64-gnu": "1.0.1",
"@rolldown/binding-linux-x64-musl": "1.0.2", "@rolldown/binding-linux-x64-musl": "1.0.1",
"@rolldown/binding-openharmony-arm64": "1.0.2", "@rolldown/binding-openharmony-arm64": "1.0.1",
"@rolldown/binding-wasm32-wasi": "1.0.2", "@rolldown/binding-wasm32-wasi": "1.0.1",
"@rolldown/binding-win32-arm64-msvc": "1.0.2", "@rolldown/binding-win32-arm64-msvc": "1.0.1",
"@rolldown/binding-win32-x64-msvc": "1.0.2" "@rolldown/binding-win32-x64-msvc": "1.0.1"
} }
}, },
"node_modules/sass": { "node_modules/sass": {
@@ -6050,15 +6050,15 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "8.0.14", "version": "8.0.13",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"picomatch": "^4.0.4", "picomatch": "^4.0.4",
"postcss": "^8.5.15", "postcss": "^8.5.14",
"rolldown": "1.0.2", "rolldown": "1.0.1",
"tinyglobby": "^0.2.16" "tinyglobby": "^0.2.16"
}, },
"bin": { "bin": {
@@ -6233,19 +6233,19 @@
} }
}, },
"node_modules/vitest": { "node_modules/vitest": {
"version": "4.1.7", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.7.tgz", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz",
"integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitest/expect": "4.1.7", "@vitest/expect": "4.1.6",
"@vitest/mocker": "4.1.7", "@vitest/mocker": "4.1.6",
"@vitest/pretty-format": "4.1.7", "@vitest/pretty-format": "4.1.6",
"@vitest/runner": "4.1.7", "@vitest/runner": "4.1.6",
"@vitest/snapshot": "4.1.7", "@vitest/snapshot": "4.1.6",
"@vitest/spy": "4.1.7", "@vitest/spy": "4.1.6",
"@vitest/utils": "4.1.7", "@vitest/utils": "4.1.6",
"es-module-lexer": "^2.0.0", "es-module-lexer": "^2.0.0",
"expect-type": "^1.3.0", "expect-type": "^1.3.0",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
@@ -6273,12 +6273,12 @@
"@edge-runtime/vm": "*", "@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0", "@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
"@vitest/browser-playwright": "4.1.7", "@vitest/browser-playwright": "4.1.6",
"@vitest/browser-preview": "4.1.7", "@vitest/browser-preview": "4.1.6",
"@vitest/browser-webdriverio": "4.1.7", "@vitest/browser-webdriverio": "4.1.6",
"@vitest/coverage-istanbul": "4.1.7", "@vitest/coverage-istanbul": "4.1.6",
"@vitest/coverage-v8": "4.1.7", "@vitest/coverage-v8": "4.1.6",
"@vitest/ui": "4.1.7", "@vitest/ui": "4.1.6",
"happy-dom": "*", "happy-dom": "*",
"jsdom": "*", "jsdom": "*",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0" "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -40,10 +40,6 @@ abstract class CollectionMutableAbstract extends NodeMutableAbstract implements
// Copy all property values // Copy all property values
$this->properties->setLabel($value->getLabel()); $this->properties->setLabel($value->getLabel());
$this->properties->setDescription($value->getDescription());
$this->properties->setRank($value->getRank());
$this->properties->setVisibility($value->getVisibility());
$this->properties->setColor($value->getColor());
return $this; return $this;
} }
@@ -20,53 +20,57 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
*/ */
abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface { abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface {
public const JSON_TYPE = CollectionPropertiesBaseInterface::JSON_TYPE;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function content(): array { public function content(): CollectionContent {
$content = $this->data[self::PROPERTY_CONTENT] ?? null; $content = $this->data[self::JSON_PROPERTY_CONTENTS] ?? null;
if (is_array($content)) { if ($content instanceof CollectionContent) {
return array_filter(array_map(function ($item) { return $content;
return $item instanceof CollectionContent ? $item : CollectionContent::tryFrom($item);
}, $content));
} else {
return [];
} }
if (is_string($content)) {
return CollectionContent::tryFrom($content) ?? CollectionContent::Event;
}
return CollectionContent::Event;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getLabel(): string { public function getLabel(): string {
return $this->data[self::PROPERTY_LABEL] ?? ''; return $this->data[self::JSON_PROPERTY_LABEL] ?? '';
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getDescription(): ?string { public function getDescription(): ?string {
return $this->data[self::PROPERTY_DESCRIPTION] ?? null; return $this->data[self::JSON_PROPERTY_DESCRIPTION] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getRank(): ?int { public function getPriority(): ?int {
return $this->data[self::PROPERTY_RANK] ?? null; return $this->data[self::JSON_PROPERTY_PRIORITY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getVisibility(): ?bool { public function getVisibility(): ?bool {
return $this->data[self::PROPERTY_VISIBILITY] ?? null; return $this->data[self::JSON_PROPERTY_VISIBILITY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getColor(): ?string { public function getColor(): ?string {
return $this->data[self::PROPERTY_COLOR] ?? null; return $this->data[self::JSON_PROPERTY_COLOR] ?? null;
} }
} }
@@ -14,22 +14,15 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface { interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'chrono:collection'; public const JSON_TYPE = 'chrono:collection';
public const PROPERTY_CONTENT = 'content'; public const JSON_PROPERTY_CONTENTS = 'content';
public const PROPERTY_LABEL = 'label'; public const JSON_PROPERTY_LABEL = 'label';
public const PROPERTY_DESCRIPTION = 'description'; public const JSON_PROPERTY_DESCRIPTION = 'description';
public const PROPERTY_RANK = 'rank'; public const JSON_PROPERTY_PRIORITY = 'priority';
public const PROPERTY_VISIBILITY = 'visibility'; public const JSON_PROPERTY_VISIBILITY = 'visibility';
public const PROPERTY_COLOR = 'color'; public const JSON_PROPERTY_COLOR = 'color';
/** public function content(): CollectionContent;
* Gets the content type of this collection
*
* @since 2025.05.01
*
* @return CollectionContent[] Returns an array of content types, a single content type, or null if not set
*/
public function content(): array;
/** /**
* Gets the human friendly name of this collection (e.g. Personal Calendar) * Gets the human friendly name of this collection (e.g. Personal Calendar)
@@ -46,11 +39,11 @@ interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface
public function getDescription(): ?string; public function getDescription(): ?string;
/** /**
* Gets the rank of this collection * Gets the priority of this collection
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
public function getRank(): ?int; public function getPriority(): ?int;
/** /**
* Gets the visibility of this collection * Gets the visibility of this collection
@@ -33,7 +33,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setLabel(string $value): static { public function setLabel(string $value): static {
$this->data[self::PROPERTY_LABEL] = $value; $this->data[self::JSON_PROPERTY_LABEL] = $value;
return $this; return $this;
} }
@@ -41,15 +41,15 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setDescription(?string $value): static { public function setDescription(?string $value): static {
$this->data[self::PROPERTY_DESCRIPTION] = $value; $this->data[self::JSON_PROPERTY_DESCRIPTION] = $value;
return $this; return $this;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function setRank(?int $value): static { public function setPriority(?int $value): static {
$this->data[self::PROPERTY_RANK] = $value; $this->data[self::JSON_PROPERTY_PRIORITY] = $value;
return $this; return $this;
} }
@@ -57,7 +57,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setVisibility(?bool $value): static { public function setVisibility(?bool $value): static {
$this->data[self::PROPERTY_VISIBILITY] = $value; $this->data[self::JSON_PROPERTY_VISIBILITY] = $value;
return $this; return $this;
} }
@@ -65,7 +65,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setColor(?string $value): static { public function setColor(?string $value): static {
$this->data[self::PROPERTY_COLOR] = $value; $this->data[self::JSON_PROPERTY_COLOR] = $value;
return $this; return $this;
} }
@@ -30,11 +30,11 @@ interface CollectionPropertiesMutableInterface extends CollectionPropertiesBaseI
public function setDescription(?string $value): static; public function setDescription(?string $value): static;
/** /**
* Sets the rank of this collection * Sets the priority of this collection
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
public function setRank(?int $value): static; public function setPriority(?int $value): static;
/** /**
* Sets the visibility of this collection * Sets the visibility of this collection
@@ -9,24 +9,18 @@ declare(strict_types=1);
namespace KTXF\Chrono\Entity; namespace KTXF\Chrono\Entity;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeBaseAbstract; use KTXF\Resource\Provider\Node\NodeBaseAbstract;
/** /**
* Abstract Chrono Entity Base Class * Abstract Chrono Entity Base Class
* *
* Provides common implementation for chrono entities * Provides common implementation for chrono entities
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface { abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface {
protected string $type = 'chrono:entity'; protected EntityPropertiesBaseAbstract $properties;
protected EntityPropertiesBaseInterface $properties;
protected function nodeIdentifier(): EntityIdentifier {
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], $this->data[static::PROPERTY_COLLECTION], $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
@@ -13,6 +13,8 @@ use KTXF\Resource\Provider\Node\NodeBaseInterface;
interface EntityBaseInterface extends NodeBaseInterface { interface EntityBaseInterface extends NodeBaseInterface {
public const JSON_TYPE = 'chrono.entity';
/** /**
* Gets the entity properties * Gets the entity properties
* *
@@ -9,25 +9,21 @@ declare(strict_types=1);
namespace KTXF\Chrono\Entity; namespace KTXF\Chrono\Entity;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeMutableAbstract; use KTXF\Resource\Provider\Node\NodeMutableAbstract;
use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface; use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
/** /**
* Abstract Chrono Entity Mutable Class * Abstract Chrono Entity Mutable Class
* *
* Provides common implementation for mutable chrono entities * Provides common implementation for mutable chrono entities
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface { abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface {
protected string $type = 'chrono:entity'; public const JSON_TYPE = EntityMutableInterface::JSON_TYPE;
protected EntityPropertiesMutableInterface $properties;
protected function nodeIdentifier(): EntityIdentifier { protected EntityPropertiesMutableAbstract $properties;
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], (string) $this->data[static::PROPERTY_COLLECTION], (string) $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
@@ -44,7 +40,7 @@ abstract class EntityMutableAbstract extends NodeMutableAbstract implements Enti
throw new \InvalidArgumentException('Properties must implement EntityPropertiesMutableInterface'); throw new \InvalidArgumentException('Properties must implement EntityPropertiesMutableInterface');
} }
$this->properties = $value; $this->properties->setDataRaw($value->getDataRaw());
return $this; return $this;
} }
@@ -16,6 +16,8 @@ use KTXF\Resource\Provider\Node\NodeMutableInterface;
*/ */
interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface { interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface {
public const JSON_TYPE = EntityBaseInterface::JSON_TYPE;
/** /**
* Gets the entity properties (mutable) * Gets the entity properties (mutable)
* *
@@ -13,10 +13,9 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
abstract class EntityPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements EntityPropertiesBaseInterface { abstract class EntityPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements EntityPropertiesBaseInterface {
/** public const JSON_TYPE = EntityPropertiesBaseInterface::JSON_TYPE;
* @inheritDoc
*/
public function getDataRaw(): array|string|null { public function getDataRaw(): array|string|null {
return $this->data[self::PROPERTY_DATA] ?? null; return $this->data[self::JSON_PROPERTY_DATA] ?? null;
} }
} }
@@ -14,7 +14,7 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
interface EntityPropertiesBaseInterface extends NodePropertiesBaseInterface { interface EntityPropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'chrono:entity'; public const JSON_TYPE = 'chrono:entity';
public const PROPERTY_DATA = 'data'; public const JSON_PROPERTY_DATA = 'data';
public function getDataRaw(): array|string|null; public function getDataRaw(): array|string|null;
@@ -24,7 +24,7 @@ abstract class EntityPropertiesMutableAbstract extends EntityPropertiesBaseAbstr
} }
public function setDataRaw(array|string|null $value): static { public function setDataRaw(array|string|null $value): static {
$this->data[self::PROPERTY_DATA] = $value; $this->data[self::JSON_PROPERTY_DATA] = $value;
return $this; return $this;
} }
} }
@@ -13,6 +13,8 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
interface EntityPropertiesMutableInterface extends EntityPropertiesBaseInterface, NodePropertiesMutableInterface { interface EntityPropertiesMutableInterface extends EntityPropertiesBaseInterface, NodePropertiesMutableInterface {
public const JSON_TYPE = EntityPropertiesBaseInterface::JSON_TYPE;
public function setDataRaw(array|string|null $value): static; public function setDataRaw(array|string|null $value): static;
} }
@@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity;
use DateTimeInterface;
use KTXF\Chrono\Entity\Property\AttachmentCollection;
use KTXF\Chrono\Entity\Property\JournalStatusTypes;
use KTXF\Chrono\Entity\Property\JournalVisibilityTypes;
use KTXF\Chrono\Entity\Property\TagCollection;
use KTXF\Json\JsonSerializableObject;
class JournalObject extends JsonSerializableObject {
public string $type = 'journal';
public int $version = 1;
public ?string $urid = null;
public ?DateTimeInterface $created = null;
public ?DateTimeInterface $modified = null;
public ?string $label = null;
public ?string $description = null;
public TagCollection $tags;
public ?string $content = null;
public ?DateTimeInterface $startsOn = null;
public ?DateTimeInterface $endsOn = null;
public ?JournalStatusTypes $status = null;
public ?JournalVisibilityTypes $visibility = null;
public AttachmentCollection $attachments;
public function __construct() {
$this->tags = new TagCollection();
$this->attachments = new AttachmentCollection();
}
}
@@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use KTXF\Json\JsonSerializableCollection;
class AttachmentCollection extends JsonSerializableCollection {
public function __construct(array $data = []) {
parent::__construct($data, AttachmentObject::class, 'string');
}
}
@@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use KTXF\Json\JsonSerializableObject;
class AttachmentObject extends JsonSerializableObject {
public ?string $uri = null;
public ?string $type = null;
public ?string $label = null;
public ?int $priority = null;
}
@@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
enum JournalStatusTypes: string {
case Draft = 'draft';
case Final = 'final';
case Cancelled = 'cancelled';
}
@@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
enum JournalVisibilityTypes: string {
case Public = 'public';
case Private = 'private';
case Confidential = 'confidential';
}
@@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use KTXF\Json\JsonSerializableCollection;
class TagCollection extends JsonSerializableCollection {
public function __construct(array $data = []) {
parent::__construct($data, 'string');
}
}
@@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use DateTimeInterface;
use KTXF\Json\JsonSerializableObject;
class TaskRecurrenceObject extends JsonSerializableObject {
public ?string $frequency = null;
public ?int $interval = null;
public ?int $count = null;
public ?DateTimeInterface $until = null;
public array $byDay = [];
public array $byMonthDay = [];
public array $byMonth = [];
}
@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
enum TaskStatusTypes: string {
case NeedsAction = 'needs-action';
case InProcess = 'in-process';
case Completed = 'completed';
case Cancelled = 'cancelled';
}
@@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use KTXF\Json\JsonSerializableCollection;
class TaskSubtaskCollection extends JsonSerializableCollection {
public function __construct(array $data = []) {
parent::__construct($data, TaskSubtaskObject::class, 'string');
}
}
@@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity\Property;
use KTXF\Json\JsonSerializableObject;
class TaskSubtaskObject extends JsonSerializableObject {
public ?string $label = null;
public bool $completed = false;
public ?int $priority = null;
}
-41
View File
@@ -1,41 +0,0 @@
<?php
declare(strict_types=1);
namespace KTXF\Chrono\Entity;
use DateTimeInterface;
use KTXF\Chrono\Entity\Property\AttachmentCollection;
use KTXF\Chrono\Entity\Property\TagCollection;
use KTXF\Chrono\Entity\Property\TaskRecurrenceObject;
use KTXF\Chrono\Entity\Property\TaskStatusTypes;
use KTXF\Chrono\Entity\Property\TaskSubtaskCollection;
use KTXF\Json\JsonSerializableObject;
class TaskObject extends JsonSerializableObject {
public string $type = 'task';
public int $version = 1;
public ?string $urid = null;
public ?DateTimeInterface $created = null;
public ?DateTimeInterface $modified = null;
public ?string $label = null;
public ?string $description = null;
public TagCollection $tags;
public ?DateTimeInterface $startsOn = null;
public ?DateTimeInterface $dueOn = null;
public ?DateTimeInterface $completedOn = null;
public ?TaskStatusTypes $status = null;
public ?int $priority = null;
public ?int $progress = null;
public ?string $color = null;
public ?TaskRecurrenceObject $recurrence = null;
public TaskSubtaskCollection $subtasks;
public AttachmentCollection $attachments;
public ?string $notes = null;
public function __construct() {
$this->tags = new TagCollection();
$this->subtasks = new TaskSubtaskCollection();
$this->attachments = new AttachmentCollection();
}
}
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventAvailabilityTypes: string { enum EventAvailabilityTypes: string {
case Free = 'free'; case Free = 'free';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use DateInterval; use DateInterval;
use DateTime; use DateTime;
@@ -33,7 +33,7 @@ class EventCommonObject extends JsonSerializableObject {
public EventSensitivityTypes|null $sensitivity = null; public EventSensitivityTypes|null $sensitivity = null;
public int|null $priority = null; public int|null $priority = null;
public string|null $color = null; public string|null $color = null;
public TagCollection $tags; public EventTagCollection $tags;
public EventOrganizerObject $organizer; public EventOrganizerObject $organizer;
public EventParticipantCollection $participants; public EventParticipantCollection $participants;
public EventNotificationCollection $notifications; public EventNotificationCollection $notifications;
@@ -44,7 +44,7 @@ class EventCommonObject extends JsonSerializableObject {
$this->locationsVirtual = new EventLocationVirtualCollection(); $this->locationsVirtual = new EventLocationVirtualCollection();
$this->notifications = new EventNotificationCollection(); $this->notifications = new EventNotificationCollection();
$this->organizer = new EventOrganizerObject(); $this->organizer = new EventOrganizerObject();
$this->tags = new TagCollection(); $this->tags = new EventTagCollection();
} }
} }
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableObject; use KTXF\Json\JsonSerializableObject;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableObject; use KTXF\Json\JsonSerializableObject;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use DateTime; use DateTime;
use DateTimeImmutable; use DateTimeImmutable;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventNotificationAnchorTypes: string { enum EventNotificationAnchorTypes: string {
case Start = 'start'; case Start = 'start';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use DateInterval; use DateInterval;
use DateTime; use DateTime;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventNotificationPatterns: string { enum EventNotificationPatterns: string {
case Absolute = 'absolute'; case Absolute = 'absolute';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventNotificationTypes: string { enum EventNotificationTypes: string {
case Visual = 'visual'; case Visual = 'visual';
@@ -7,12 +7,9 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity; namespace KTXF\Chrono\Event;
use DateTimeInterface; use DateTimeInterface;
use KTXF\Chrono\Entity\Property\EventCommonObject;
use KTXF\Chrono\Entity\Property\EventMutationCollection;
use KTXF\Chrono\Entity\Property\EventOccurrenceObject;
class EventObject extends EventCommonObject { class EventObject extends EventCommonObject {
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use DateTime; use DateTime;
use DateTimeImmutable; use DateTimeImmutable;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventOccurrencePatternTypes: string { enum EventOccurrencePatternTypes: string {
case Absolute = 'absolute'; case Absolute = 'absolute';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventOccurrencePrecisionTypes: string { enum EventOccurrencePrecisionTypes: string {
case Yearly = 'yearly'; case Yearly = 'yearly';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableObject; use KTXF\Json\JsonSerializableObject;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableObject; use KTXF\Json\JsonSerializableObject;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventParticipantRealm: string { enum EventParticipantRealm: string {
case Internal = 'I'; case Internal = 'I';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventParticipantRoleTypes: string { enum EventParticipantRoleTypes: string {
case Owner = 'owner'; case Owner = 'owner';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventParticipantStatusTypes: string { enum EventParticipantStatusTypes: string {
case None = 'none'; case None = 'none';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventParticipantTypes: string { enum EventParticipantTypes: string {
case Unknown = 'unknown'; case Unknown = 'unknown';
@@ -7,7 +7,7 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\Chrono\Entity\Property; namespace KTXF\Chrono\Event;
enum EventSensitivityTypes: string { enum EventSensitivityTypes: string {
case Public = 'public'; case Public = 'public';
@@ -7,14 +7,14 @@ declare(strict_types=1);
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
namespace KTXF\People\Entity\Property; namespace KTXF\Chrono\Event;
use KTXF\Json\JsonSerializableCollection; use KTXF\Json\JsonSerializableCollection;
class TagCollection extends JsonSerializableCollection { class EventTagCollection extends JsonSerializableCollection {
public function __construct(array $data = []) { public function __construct(array $data = []) {
parent::__construct($data, 'string'); parent::__construct($data, 'string');
} }
} }
@@ -12,7 +12,7 @@ namespace KTXF\Chrono\Provider;
use KTXF\Resource\Provider\ResourceProviderBaseInterface; use KTXF\Resource\Provider\ResourceProviderBaseInterface;
/** /**
* Provider Base Interface * Chrono Provider Base Interface
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -12,9 +12,11 @@ namespace KTXF\Chrono\Provider;
use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface; use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
/** /**
* Provider Service Mutate Interface * Chrono Provider Service Mutate Interface
* *
* Optional interface for providers that support service CRUD operations * Optional interface for providers that support service CRUD operations.
*
* Implementations return ServiceMutableInterface instances (which extend ResourceServiceMutateInterface).
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -23,8 +25,11 @@ use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
* @method string serviceModify(string $tenantId, ?string $userId, ServiceMutableInterface $service) Modify a chrono service configuration * @method string serviceModify(string $tenantId, ?string $userId, ServiceMutableInterface $service) Modify a chrono service configuration
* @method bool serviceDestroy(string $tenantId, ?string $userId, ServiceMutableInterface $service) Delete a chrono service configuration * @method bool serviceDestroy(string $tenantId, ?string $userId, ServiceMutableInterface $service) Delete a chrono service configuration
*/ */
interface ProviderServiceMutateInterface extends ResourceProviderServiceMutateInterface { interface ProviderServiceMutateInterface extends ProviderBaseInterface, ResourceProviderServiceMutateInterface {
public const JSON_TYPE = ProviderBaseInterface::JSON_TYPE;
// Methods inherited from ResourceProviderServiceMutateInterface
// Implementations should return/accept ServiceMutableInterface instances
// Methods inherited from ResourceProviderServiceMutateInterface
} }
@@ -10,27 +10,36 @@ declare(strict_types=1);
namespace KTXF\Chrono\Provider; namespace KTXF\Chrono\Provider;
use KTXF\Chrono\Service\ServiceBaseInterface; use KTXF\Chrono\Service\ServiceBaseInterface;
use KTXF\Chrono\Service\ServiceMutableInterface;
/** /**
* Provider Service Test Interface * Chrono Provider Service Test Interface
* *
* Optional interface for providers that support testing service connections * Optional interface for chrono providers that support testing service connections.
* Providers implementing this interface can validate connection parameters,
* test authentication, and verify service availability before creating a
* persistent service configuration.
*
* Supports two testing modes:
* 1. Testing an existing service (validate current configuration)
* 2. Testing a fresh configuration (validate before saving)
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ProviderServiceTestInterface { interface ProviderServiceTestInterface extends ProviderBaseInterface {
public const CAPABILITY_SERVICE_TEST = 'ServiceTest';
/** /**
* Test a service connection * Test a service connection
* *
* Tests connectivity, authentication, and capabilities of a service * Tests connectivity, authentication, and capabilities of a service.
*
* For new services: use serviceFresh() to create a service, configure it with
* setters, then pass it to this method for testing before persisting.
*
* For existing services: fetch the service and pass it directly.
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param ServiceBaseInterface|ServiceMutableInterface $service Service to test (can be fresh/unsaved or existing) * @param ServiceBaseInterface $service Service to test (can be fresh/unsaved or existing)
* @param array $options Provider-specific test options: * @param array $options Provider-specific test options:
* - 'timeout' => int (seconds, default: 10) * - 'timeout' => int (seconds, default: 10)
* - 'verify_ssl' => bool (default: true) * - 'verify_ssl' => bool (default: true)
@@ -39,10 +48,10 @@ interface ProviderServiceTestInterface {
* *
* @return array Test results in the format: * @return array Test results in the format:
* [ * [
* 'disposition' => 'Success' | 'Failure' | 'Warning', * 'success' => bool,
* 'message' => 'Connection successful' | 'Error message', * 'message' => 'Connection successful' | 'Error message'
* ] * ]
*/ */
public function serviceTest(ServiceBaseInterface|ServiceMutableInterface $service, array $options = []): array; public function serviceTest(ServiceBaseInterface $service, array $options = []): array;
} }
@@ -9,21 +9,16 @@ declare(strict_types=1);
namespace KTXF\Chrono\Service; namespace KTXF\Chrono\Service;
use Generator;
use KTXF\Chrono\Collection\CollectionBaseInterface; use KTXF\Chrono\Collection\CollectionBaseInterface;
use KTXF\Chrono\Entity\EntityBaseInterface;
use KTXF\Resource\Delta\Delta; use KTXF\Resource\Delta\Delta;
use KTXF\Resource\Filter\IFilter; use KTXF\Resource\Filter\IFilter;
use KTXF\Resource\Identifier\EntityIdentifierInterface;
use KTXF\Resource\Provider\ResourceServiceBaseInterface; use KTXF\Resource\Provider\ResourceServiceBaseInterface;
use KTXF\Resource\Range\IRange; use KTXF\Resource\Range\IRange;
use KTXF\Resource\Range\RangeType; use KTXF\Resource\Range\RangeType;
use KTXF\Resource\Sort\ISort; use KTXF\Resource\Sort\ISort;
/** /**
* Service Base Interface * Chrono Service Base Interface
*
* Minimum interface for a service, providing read-only access to collections and entities.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -75,7 +70,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* @param IFilter|null $filter Optional filter criteria * @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order * @param ISort|null $sort Optional sort order
* *
* @return array<string|int,CollectionBaseInterface> Collections indexed by identifier * @return array<string|int,CollectionBaseInterface> Collections indexed by ID
*/ */
public function collectionList(string|int $location, ?IFilter $filter = null, ?ISort $sort = null): array; public function collectionList(string|int $location, ?IFilter $filter = null, ?ISort $sort = null): array;
@@ -102,9 +97,9 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int ...$identifiers Collection identifiers to check * @param string|int ...$identifiers Collection IDs to check
* *
* @return array<string|int,bool> Map of identifier => exists * @return array<string|int,bool> Map of ID => exists
*/ */
public function collectionExtant(string|int $location, string|int ...$identifiers): array; public function collectionExtant(string|int $location, string|int ...$identifiers): array;
@@ -113,44 +108,29 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $identifier Collection identifier * @param string|int $identifier Collection ID
* *
* @return CollectionBaseInterface|null Collection or null if not found * @return CollectionBaseInterface|null Collection or null if not found
*/ */
public function collectionFetch(string|int $identifier): ?CollectionBaseInterface; public function collectionFetch(string|int $identifier): ?CollectionBaseInterface;
/** /**
* Lists entities in a collection * Lists messages in a collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param IFilter|null $filter Optional filter criteria * @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order * @param ISort|null $sort Optional sort order
* @param IRange|null $range Optional pagination * @param IRange|null $range Optional pagination
* @param array|null $properties Optional entity properties to fetch * @param array|null $properties Optional message properties to fetch
* *
* @return array<string,EntityBaseInterface> Entities indexed by Urn * @return array<string|int,EntityBaseInterface> Messages indexed by ID
*/ */
public function entityListBulk(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array; public function entityList(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array;
/** /**
* Lists entities in a collection * Creates a filter builder for messages
*
* @since 2025.05.01
*
* @param string|int $collection Collection identifier
* @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order
* @param IRange|null $range Optional pagination
* @param array|null $properties Optional entity properties to fetch
*
* @return Generator Yields entities one by one as EntityBaseInterface
*/
public function entityListStream(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): Generator;
/**
* Creates a filter builder for entities
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -159,7 +139,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListFilter(): IFilter; public function entityListFilter(): IFilter;
/** /**
* Creates a sort builder for entities * Creates a sort builder for messages
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -168,7 +148,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListSort(): ISort; public function entityListSort(): ISort;
/** /**
* Creates a range builder for entities * Creates a range builder for messages
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -179,49 +159,40 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListRange(RangeType $type): IRange; public function entityListRange(RangeType $type): IRange;
/** /**
* Gets incremental changes since last signature * Gets incremental changes since last sync
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param string $signature Token from previous delta * @param string $signature Sync token from previous sync
* @param string $detail Detail level: 'ids', 'minimal', 'full'
* *
* @return array ['signature' => string, 'added' => array, 'modified' => array, 'removed' => array] * @return array ['signature' => string, 'added' => array, 'modified' => array, 'removed' => array]
*/ */
public function entityDelta(string|int $collection, string $signature): Delta; public function entityDelta(string|int $collection, string $signature, string $detail = 'ids'): Delta;
/** /**
* Checks if entities exist * Checks if messages exist
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param string|int ...$identifiers Entity identifiers to check * @param string|int ...$identifiers Message IDs to check
* *
* @return array<string|int,bool> Map of identifier => exists * @return array<string|int,bool> Map of ID => exists
*/ */
public function entityExtant(string|int $collection, string|int ...$identifiers): array; public function entityExtant(string|int $collection, string|int ...$identifiers): array;
/** /**
* Fetches one or more entities as an array * Fetches one or more entities
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param EntityIdentifierInterface ...$identifiers Entity identifiers to fetch * @param string|int $collection Collection ID
* @param string|int ...$identifiers Message IDs to fetch
* *
* @return array<string,EntityBaseInterface> Entities indexed by Urn * @return array<string|int,EntityBaseInterface> Messages indexed by ID
*/ */
public function entityFetchBulk(EntityIdentifierInterface ...$identifiers): array; public function entityFetch(string|int $collection, string|int ...$identifiers): array;
/**
* Fetches one or more entities as a stream
*
* @since 2025.05.01
*
* @param EntityIdentifierInterface ...$identifiers Entity identifiers to fetch
*
* @return Generator<string,EntityBaseInterface> Yields entities one by one
*/
public function entityFetchStream(EntityIdentifierInterface ...$identifiers): Generator;
} }
@@ -11,17 +11,13 @@ namespace KTXF\Chrono\Service;
use KTXF\Chrono\Collection\CollectionBaseInterface; use KTXF\Chrono\Collection\CollectionBaseInterface;
use KTXF\Chrono\Collection\CollectionMutableInterface; use KTXF\Chrono\Collection\CollectionMutableInterface;
use KTXF\Chrono\Collection\CollectionPropertiesBaseInterface;
use KTXF\Resource\Identifier\CollectionIdentifierInterface;
/** /**
* Service Collection Mutable Interface * Chrono Service Collection Mutable Interface
*
* Optional interface for services that support collection CRUD operations.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ServiceCollectionMutableInterface { interface ServiceCollectionMutableInterface extends ServiceBaseInterface {
public const CAPABILITY_COLLECTION_CREATE = 'CollectionCreate'; public const CAPABILITY_COLLECTION_CREATE = 'CollectionCreate';
public const CAPABILITY_COLLECTION_UPDATE = 'CollectionUpdate'; public const CAPABILITY_COLLECTION_UPDATE = 'CollectionUpdate';
@@ -41,36 +37,37 @@ interface ServiceCollectionMutableInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param CollectionIdentifierInterface|null $target Target collection identifier (parent) * @param string|int|null $location Parent collection ID (null for root)
* @param CollectionPropertiesBaseInterface $properties Collection properties * @param CollectionMutableInterface $collection Collection to create
* @param array $options Protocol-specific options * @param array $options Protocol-specific options
* *
* @return CollectionBaseInterface Created collection with assigned ID * @return CollectionBaseInterface Created collection with assigned ID
*/ */
public function collectionCreate(CollectionIdentifierInterface|null $target, CollectionPropertiesBaseInterface $properties, array $options = []): CollectionBaseInterface; public function collectionCreate(string|int|null $location, CollectionMutableInterface $collection, array $options = []): CollectionBaseInterface;
/** /**
* Updates an existing collection * Updates an existing collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param CollectionIdentifierInterface $target Target collection identifier * @param string|int $identifier Collection ID
* @param CollectionPropertiesBaseInterface $properties Updated collection data * @param CollectionMutableInterface $collection Updated collection data
* *
* @return CollectionBaseInterface Updated collection * @return CollectionBaseInterface Updated collection
*/ */
public function collectionUpdate(CollectionIdentifierInterface $target, CollectionPropertiesBaseInterface $properties): CollectionBaseInterface; public function collectionUpdate(string|int $identifier, CollectionMutableInterface $collection): CollectionBaseInterface;
/** /**
* Deletes a collection * Deletes a collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param CollectionIdentifierInterface $target Target collection identifier * @param string|int $identifier Collection ID
* @param bool $force Force deletion even if not empty * @param bool $force Force deletion even if not empty
* @param bool $recursive Recursively delete contents
* *
* @return CollectionBaseInterface|true Collection object on soft delete, true on hard delete * @return bool True if deleted
*/ */
public function collectionDelete(CollectionIdentifierInterface $target, bool $force = false): CollectionBaseInterface | true; public function collectionDelete(string|int $identifier, bool $force = false, bool $recursive = false): bool;
} }
@@ -12,12 +12,15 @@ namespace KTXF\Chrono\Service;
use KTXF\Resource\Provider\ResourceServiceConfigureInterface; use KTXF\Resource\Provider\ResourceServiceConfigureInterface;
/** /**
* Service Configurable Interface * Chrono Service Configurable Interface
* *
* Extends base service interface with setter methods for mutable properties * Extends base service interface with setter methods for mutable properties.
* Used for service configuration and updates.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ServiceConfigurableInterface extends ServiceMutableInterface, ResourceServiceConfigureInterface { interface ServiceConfigurableInterface extends ServiceMutableInterface, ResourceServiceConfigureInterface {
public const JSON_TYPE = ServiceBaseInterface::JSON_TYPE;
} }
@@ -11,21 +11,19 @@ namespace KTXF\Chrono\Service;
use KTXF\Chrono\Entity\EntityBaseInterface; use KTXF\Chrono\Entity\EntityBaseInterface;
use KTXF\Chrono\Entity\EntityMutableInterface; use KTXF\Chrono\Entity\EntityMutableInterface;
use KTXF\Chrono\Entity\EntityPropertiesMutableInterface;
use KTXF\Resource\Identifier\CollectionIdentifierInterface;
use KTXF\Resource\Identifier\EntityIdentifierInterface;
/** /**
* Service Entity Mutable Interface * Chrono Service Entity Mutable Interface
* *
* Optional interface for services that support entity CRUD operations * Optional interface for services that support entity CRUD operations.
* Provides entity creation, modification, deletion, copying, moving, and flag management.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ServiceEntityMutableInterface { interface ServiceEntityMutableInterface extends ServiceBaseInterface {
public const CAPABILITY_ENTITY_CREATE = 'EntityCreate'; public const CAPABILITY_ENTITY_CREATE = 'EntityCreate';
public const CAPABILITY_ENTITY_MODIFY = 'EntityModify'; public const CAPABILITY_ENTITY_UPDATE = 'EntityUpdate';
public const CAPABILITY_ENTITY_DELETE = 'EntityDelete'; public const CAPABILITY_ENTITY_DELETE = 'EntityDelete';
public const CAPABILITY_ENTITY_COPY = 'EntityCopy'; public const CAPABILITY_ENTITY_COPY = 'EntityCopy';
public const CAPABILITY_ENTITY_MOVE = 'EntityMove'; public const CAPABILITY_ENTITY_MOVE = 'EntityMove';
@@ -44,71 +42,36 @@ interface ServiceEntityMutableInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param CollectionIdentifierInterface $target Target collection identifier * @param string|int $collection collection identifier
* @param EntityPropertiesMutableInterface $properties Entity properties * @param EntityMutableInterface $entity Entity data
* @param array $options Additional options * @param array $options additional options
* *
* @return EntityBaseInterface Created entity * @return EntityBaseInterface Created entity
*/ */
public function entityCreate(CollectionIdentifierInterface $target, EntityPropertiesMutableInterface $properties, array $options = []): EntityBaseInterface; public function entityCreate(string|int $collection, EntityMutableInterface $entity, array $options = []): EntityBaseInterface;
/** /**
* Modifies an existing entity * Modifies an existing entity
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param EntityIdentifierInterface $target Target entity identifier * @param string|int $collection Collection identifier
* @param EntityPropertiesMutableInterface $properties Entity properties to update * @param string|int $identifier Entity identifier
* @param EntityMutableInterface $entity Entity data
* *
* @return EntityBaseInterface Modified entity * @return EntityBaseInterface Modified entity
*/ */
public function entityModify(EntityIdentifierInterface $target, EntityPropertiesMutableInterface $properties): EntityBaseInterface; public function entityUpdate(string|int $collection, string|int $identifier, EntityMutableInterface $entity): EntityBaseInterface;
/** /**
* Deletes entities * Deletes an existing entity in the specified collection
*
* @since 2026.04.01
*
* @param EntityIdentifierInterface ...$targets Source entities to delete
*
* @return array<string, array{
* disposition: 'moved'|'deleted'|'error',
* destination: ?CollectionIdentifierInterface,
* mutation: EntityIdentifierInterface
* }> Results keyed by source entity identifier
*/
public function entityDelete(EntityIdentifierInterface ...$targets): array;
/**
* Moves entities to another collection
*
* @since 2025.05.01
*
* @param CollectionIdentifierInterface $target Target collection identifier
* @param EntityIdentifierInterface ...$sources Source entities to move
*
* @return array<string, array{
* disposition: 'moved'|'error',
* destination: ?CollectionIdentifierInterface,
* mutation: EntityIdentifierInterface
* }> Results keyed by source entity identifier
*/
public function entityMove(CollectionIdentifierInterface $target, EntityIdentifierInterface ...$sources): array;
/**
* Copies entities to another collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param CollectionIdentifierInterface $target Target collection identifier * @param string|int $collection Collection identifier
* @param EntityIdentifierInterface ...$sources Source entities to copy * @param string|int $identifier Entity identifier to delete
* *
* @return array<string, array{ * @return EntityBaseInterface Deleted entity
* disposition: 'copied'|'error',
* destination: ?CollectionIdentifierInterface,
* mutation: EntityIdentifierInterface
* }> Results keyed by source entity identifier
*/ */
public function entityCopy(CollectionIdentifierInterface $target, EntityIdentifierInterface ...$sources): array; public function entityDelete(string|int $collection, string|int $identifier): EntityBaseInterface;
} }
@@ -12,10 +12,11 @@ namespace KTXF\Chrono\Service;
/** /**
* Chrono Service Mutable Interface * Chrono Service Mutable Interface
* *
* Extends base service interface with setter methods for mutable properties * Extends base service interface with setter methods for mutable properties.
* Used for service configuration and updates.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ServiceMutableInterface { interface ServiceMutableInterface extends ServiceBaseInterface {
} }
+10 -10
View File
@@ -14,16 +14,16 @@ use DateTimeImmutable;
interface INodeBase extends \JsonSerializable { interface INodeBase extends \JsonSerializable {
public const JSON_TYPE = 'files.node'; public const JSON_TYPE = 'files.node';
public const PROPERTY_TYPE = '@type'; public const JSON_PROPERTY_TYPE = '@type';
public const PROPERTY_IN = 'in'; public const JSON_PROPERTY_IN = 'in';
public const PROPERTY_ID = 'id'; public const JSON_PROPERTY_ID = 'id';
public const PROPERTY_CREATED_ON = 'createdOn'; public const JSON_PROPERTY_CREATED_ON = 'createdOn';
public const PROPERTY_CREATED_BY = 'createdBy'; public const JSON_PROPERTY_CREATED_BY = 'createdBy';
public const PROPERTY_MODIFIED_ON = 'modifiedOn'; public const JSON_PROPERTY_MODIFIED_ON = 'modifiedOn';
public const PROPERTY_MODIFIED_BY = 'modifiedBy'; public const JSON_PROPERTY_MODIFIED_BY = 'modifiedBy';
public const PROPERTY_OWNER = 'owner'; public const JSON_PROPERTY_OWNER = 'owner';
public const PROPERTY_SIGNATURE = 'signature'; public const JSON_PROPERTY_SIGNATURE = 'signature';
public const PROPERTY_LABEL = 'label'; public const JSON_PROPERTY_LABEL = 'label';
/** /**
* Unique identifier of the parent node (folder) this node belongs to * Unique identifier of the parent node (folder) this node belongs to
+4 -4
View File
@@ -18,10 +18,10 @@ namespace KTXF\Files\Node;
interface INodeEntityBase extends INodeBase { interface INodeEntityBase extends INodeBase {
public const JSON_TYPE = 'files.entity'; public const JSON_TYPE = 'files.entity';
public const PROPERTY_SIZE = 'size'; public const JSON_PROPERTY_SIZE = 'size';
public const PROPERTY_MIME = 'mime'; public const JSON_PROPERTY_MIME = 'mime';
public const PROPERTY_FORMAT = 'format'; public const JSON_PROPERTY_FORMAT = 'format';
public const PROPERTY_ENCODING = 'encoding'; public const JSON_PROPERTY_ENCODING = 'encoding';
/** /**
* File size in bytes * File size in bytes
@@ -14,15 +14,15 @@ use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeBaseAbstract; use KTXF\Resource\Provider\Node\NodeBaseAbstract;
/** /**
* Abstract Entity Base Class * Abstract Mail Entity Base Class
* *
* Provides common implementation for entities * Provides common implementation for mail entities
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface { abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface {
protected string $type = 'mail:entity'; protected string $type = 'mail.entity';
protected MessagePropertiesBaseInterface $properties; protected MessagePropertiesBaseInterface $properties;
protected function nodeIdentifier(): EntityIdentifier { protected function nodeIdentifier(): EntityIdentifier {
@@ -15,15 +15,15 @@ use KTXF\Resource\Provider\Node\NodeMutableAbstract;
use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface; use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
/** /**
* Abstract Entity Mutable Class * Abstract Mail Entity Mutable Class
* *
* Provides common implementation for mutable entities * Provides common implementation for mutable mail entities
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface { abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface {
protected string $type = 'mail:entity'; protected string $type = 'mail.entity';
protected MessagePropertiesMutableInterface $properties; protected MessagePropertiesMutableInterface $properties;
protected function nodeIdentifier(): EntityIdentifier { protected function nodeIdentifier(): EntityIdentifier {
+13 -20
View File
@@ -25,6 +25,16 @@ class Address implements AddressInterface {
private ?string $name = null, private ?string $name = null,
) {} ) {}
/**
* @inheritDoc
*/
public function jsonSerialize(): array {
return array_filter([
self::JSON_PROPERTY_ADDRESS => $this->address,
self::JSON_PROPERTY_LABEL => $this->name,
], fn($v) => $v !== null && $v !== '');
}
/** /**
* Creates an Address from a formatted string * Creates an Address from a formatted string
* *
@@ -56,34 +66,17 @@ class Address implements AddressInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param array<address: string, label: string|null> $data * @param array $data Array with 'address' and optional 'name' keys
* *
* @return self * @return self
*/ */
public static function fromArray(array $data): self { public static function fromArray(array $data): self {
return new self( return new self(
$data[self::PROPERTY_ADDRESS] ?? $data['address'] ?? '', $data[self::JSON_PROPERTY_ADDRESS] ?? $data['address'] ?? '',
$data[self::PROPERTY_LABEL] ?? $data['label'] ?? null, $data[self::JSON_PROPERTY_LABEL] ?? $data['name'] ?? null,
); );
} }
/**
* @inheritDoc
*/
public function jsonSerialize(): array {
return array_filter([
self::PROPERTY_ADDRESS => $this->address,
self::PROPERTY_LABEL => $this->name,
], fn($v) => $v !== null && $v !== '');
}
/**
* @inheritDoc
*/
public function toArray(): array {
return $this->jsonSerialize();
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
+2 -9
View File
@@ -20,15 +20,8 @@ use KTXF\Json\JsonSerializable;
*/ */
interface AddressInterface extends JsonSerializable { interface AddressInterface extends JsonSerializable {
public const PROPERTY_ADDRESS = 'address'; public const JSON_PROPERTY_ADDRESS = 'address';
public const PROPERTY_LABEL = 'label'; public const JSON_PROPERTY_LABEL = 'label';
/*
* Converts the Address to an array representation
*
* @return array<address: string, label: string|null>
*/
public function toArray(): array;
/** /**
* Gets the email address * Gets the email address
+194
View File
@@ -0,0 +1,194 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Object;
/**
* Attachment Implementation
*
* @since 2025.05.01
*/
class Attachment implements AttachmentInterface {
/**
* @param string $name File name
* @param string $mimeType MIME type
* @param string $content Binary content
* @param string|null $id Attachment ID
* @param int|null $size Size in bytes
* @param string|null $contentId Content-ID for inline attachments
* @param bool $inline Whether inline attachment
*/
public function __construct(
private string $name,
private string $mimeType,
private string $content,
private ?string $id = null,
private ?int $size = null,
private ?string $contentId = null,
private bool $inline = false,
) {
if ($this->size === null) {
$this->size = strlen($this->content);
}
}
/**
* @inheritDoc
*/
public function jsonSerialize(): array {
return array_filter([
self::JSON_PROPERTY_ID => $this->id,
self::JSON_PROPERTY_NAME => $this->name,
self::JSON_PROPERTY_MIME_TYPE => $this->mimeType,
self::JSON_PROPERTY_SIZE => $this->size,
self::JSON_PROPERTY_CONTENT_ID => $this->contentId,
self::JSON_PROPERTY_INLINE => $this->inline ?: null,
'contentBase64' => $this->getContentBase64(),
], fn($v) => $v !== null);
}
/**
* Creates an attachment from a file path
*
* @since 2025.05.01
*
* @param string $path File path
* @param string|null $name Override file name
* @param string|null $mimeType Override MIME type
*
* @return self
*/
public static function fromFile(string $path, ?string $name = null, ?string $mimeType = null): self {
$content = file_get_contents($path);
$name = $name ?? basename($path);
$mimeType = $mimeType ?? mime_content_type($path) ?: 'application/octet-stream';
return new self($name, $mimeType, $content);
}
/**
* Creates an attachment from base64 encoded content
*
* @since 2025.05.01
*
* @param string $name File name
* @param string $mimeType MIME type
* @param string $base64Content Base64 encoded content
*
* @return self
*/
public static function fromBase64(string $name, string $mimeType, string $base64Content): self {
return new self($name, $mimeType, base64_decode($base64Content));
}
/**
* Creates an inline attachment for embedding in HTML
*
* @since 2025.05.01
*
* @param string $name File name
* @param string $mimeType MIME type
* @param string $content Binary content
* @param string $contentId Content-ID (without cid: prefix)
*
* @return self
*/
public static function inline(string $name, string $mimeType, string $content, string $contentId): self {
return new self($name, $mimeType, $content, null, null, $contentId, true);
}
/**
* Creates from array data
*
* @since 2025.05.01
*
* @param array $data
*
* @return self
*/
public static function fromArray(array $data): self {
$content = $data['content'] ?? '';
if (isset($data['contentBase64'])) {
$content = base64_decode($data['contentBase64']);
}
return new self(
$data[self::JSON_PROPERTY_NAME] ?? $data['name'] ?? '',
$data[self::JSON_PROPERTY_MIME_TYPE] ?? $data['mimeType'] ?? 'application/octet-stream',
$content,
$data[self::JSON_PROPERTY_ID] ?? $data['id'] ?? null,
$data[self::JSON_PROPERTY_SIZE] ?? $data['size'] ?? null,
$data[self::JSON_PROPERTY_CONTENT_ID] ?? $data['contentId'] ?? null,
$data[self::JSON_PROPERTY_INLINE] ?? $data['inline'] ?? false,
);
}
/**
* @inheritDoc
*/
public function getId(): ?string {
return $this->id;
}
/**
* @inheritDoc
*/
public function getName(): string {
return $this->name;
}
/**
* @inheritDoc
*/
public function getMimeType(): string {
return $this->mimeType;
}
/**
* @inheritDoc
*/
public function getSize(): ?int {
return $this->size;
}
/**
* @inheritDoc
*/
public function getContentId(): ?string {
return $this->contentId;
}
/**
* @inheritDoc
*/
public function isInline(): bool {
return $this->inline;
}
/**
* @inheritDoc
*/
public function getContent(): string {
return $this->content;
}
/**
* Gets the content as base64 encoded string
*
* @since 2025.05.01
*
* @return string
*/
public function getContentBase64(): string {
return base64_encode($this->content);
}
}
@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Object;
use KTXF\Json\JsonSerializable;
/**
* Attachment Interface
*
* Represents a file attachment on a mail message.
*
* @since 2025.05.01
*/
interface AttachmentInterface extends JsonSerializable {
public const JSON_PROPERTY_ID = 'id';
public const JSON_PROPERTY_NAME = 'name';
public const JSON_PROPERTY_MIME_TYPE = 'mimeType';
public const JSON_PROPERTY_SIZE = 'size';
public const JSON_PROPERTY_CONTENT_ID = 'contentId';
public const JSON_PROPERTY_INLINE = 'inline';
/**
* Gets the attachment identifier
*
* @since 2025.05.01
*
* @return string|null Attachment ID or null for new attachments
*/
public function getId(): ?string;
/**
* Gets the file name
*
* @since 2025.05.01
*
* @return string File name (e.g., "document.pdf")
*/
public function getName(): string;
/**
* Gets the MIME type
*
* @since 2025.05.01
*
* @return string MIME type (e.g., "application/pdf")
*/
public function getMimeType(): string;
/**
* Gets the file size in bytes
*
* @since 2025.05.01
*
* @return int|null Size in bytes or null if unknown
*/
public function getSize(): ?int;
/**
* Gets the Content-ID for inline attachments
*
* @since 2025.05.01
*
* @return string|null Content-ID for referencing in HTML body (e.g., "cid:image1")
*/
public function getContentId(): ?string;
/**
* Checks if this is an inline attachment (embedded in body)
*
* @since 2025.05.01
*
* @return bool True if inline, false if regular attachment
*/
public function isInline(): bool;
/**
* Gets the attachment content
*
* @since 2025.05.01
*
* @return string Binary content of the attachment
*/
public function getContent(): string;
}
-37
View File
@@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Object;
/**
* Shared Message Part implementation matching the frontend JSON shape.
*/
class MessagePart extends MessagePartMutableAbstract {
public static function fromArray(array $data): self {
$part = new self();
$part->data = $data;
if (isset($part->data[MessagePartInterface::PROPERTY_SUB_PARTS]) && is_array($part->data[MessagePartInterface::PROPERTY_SUB_PARTS])) {
foreach ($part->data[MessagePartInterface::PROPERTY_SUB_PARTS] as $entry) {
if (is_object($entry)) {
$entry = get_object_vars($entry);
}
if (is_array($entry)) {
$part->parts[] = self::fromArray($entry);
}
}
unset($part->data[MessagePartInterface::PROPERTY_SUB_PARTS]);
}
return $part;
}
}
@@ -32,9 +32,9 @@ abstract class MessagePartBaseAbstract implements MessagePartInterface {
/** /**
* Constructor * Constructor
* *
* @param array|null &$data Reference to data array * @param array &$data Reference to data array
*/ */
public function __construct(array|null &$data = null) { public function __construct(array &$data = null) {
if ($data === null) { if ($data === null) {
$data = []; $data = [];
} }
@@ -52,70 +52,49 @@ abstract class MessagePartBaseAbstract implements MessagePartInterface {
* @inheritDoc * @inheritDoc
*/ */
public function getId(): ?string { public function getId(): ?string {
return $this->data[MessagePartInterface::PROPERTY_PART_ID] ?? null; return $this->data['partId'] ?? null;
}
/**
* @inheritDoc
*/
public function getSize(): ?int {
return $this->data[MessagePartInterface::PROPERTY_SIZE] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getType(): ?string { public function getType(): ?string {
return $this->data[MessagePartInterface::PROPERTY_TYPE] ?? null; return $this->data['type'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getDisposition(): ?string { public function getDisposition(): ?string {
return $this->data[MessagePartInterface::PROPERTY_DISPOSITION] ?? null; return $this->data['disposition'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getName(): ?string { public function getName(): ?string {
return $this->data[MessagePartInterface::PROPERTY_NAME] ?? null; return $this->data['name'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getCharset(): ?string { public function getCharset(): ?string {
return $this->data[MessagePartInterface::PROPERTY_CHARSET] ?? null; return $this->data['charset'] ?? null;
}
/**
* @inheritDoc
*/
public function getContentId(): ?string {
return $this->data[MessagePartInterface::PROPERTY_CONTENT_ID] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getLanguage(): ?string { public function getLanguage(): ?string {
return $this->data[MessagePartInterface::PROPERTY_LANGUAGE] ?? null; return $this->data['language'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getLocation(): ?string { public function getLocation(): ?string {
return $this->data[MessagePartInterface::PROPERTY_LOCATION] ?? null; return $this->data['location'] ?? null;
}
/**
* @inheritDoc
*/
public function getContent(): ?string {
return $this->data[MessagePartInterface::PROPERTY_CONTENT] ?? null;
} }
/** /**
@@ -132,9 +111,9 @@ abstract class MessagePartBaseAbstract implements MessagePartInterface {
$result = $this->data; $result = $this->data;
if (!empty($this->parts)) { if (!empty($this->parts)) {
$result[MessagePartInterface::PROPERTY_SUB_PARTS] = []; $result['subParts'] = [];
foreach ($this->parts as $part) { foreach ($this->parts as $part) {
$result[MessagePartInterface::PROPERTY_SUB_PARTS][] = $part->jsonSerialize(); $result['subParts'][] = $part->jsonSerialize();
} }
} }
@@ -20,19 +20,6 @@ use KTXF\Json\JsonSerializable;
*/ */
interface MessagePartInterface extends JsonSerializable { interface MessagePartInterface extends JsonSerializable {
public const PROPERTY_PART_ID = 'partId';
public const PROPERTY_BLOB_ID = 'blobId';
public const PROPERTY_SIZE = 'size';
public const PROPERTY_NAME = 'name';
public const PROPERTY_TYPE = 'type';
public const PROPERTY_CHARSET = 'charset';
public const PROPERTY_DISPOSITION = 'disposition';
public const PROPERTY_CONTENT_ID = 'cid';
public const PROPERTY_LANGUAGE = 'language';
public const PROPERTY_LOCATION = 'location';
public const PROPERTY_CONTENT = 'content';
public const PROPERTY_SUB_PARTS = 'subParts';
/** /**
* Gets the blob identifier * Gets the blob identifier
* *
@@ -51,15 +38,6 @@ interface MessagePartInterface extends JsonSerializable {
*/ */
public function getId(): ?string; public function getId(): ?string;
/**
* Gets the part size in bytes
*
* @since 2026.06.15
*
* @return int|null
*/
public function getSize(): ?int;
/** /**
* Gets the MIME type * Gets the MIME type
* *
@@ -78,15 +56,6 @@ interface MessagePartInterface extends JsonSerializable {
*/ */
public function getDisposition(): ?string; public function getDisposition(): ?string;
/**
* Gets the Content-ID for inline parts
*
* @since 2026.06.15
*
* @return string|null
*/
public function getContentId(): ?string;
/** /**
* Gets the part name * Gets the part name
* *
@@ -123,15 +92,6 @@ interface MessagePartInterface extends JsonSerializable {
*/ */
public function getLocation(): ?string; public function getLocation(): ?string;
/**
* Gets the decoded part content
*
* @since 2026.06.15
*
* @return string|null
*/
public function getContent(): ?string;
/** /**
* Gets the sub-parts * Gets the sub-parts
* *
@@ -46,16 +46,6 @@ abstract class MessagePartMutableAbstract extends MessagePartBaseAbstract {
return $this; return $this;
} }
/**
* Sets the part size
*
* @since 2026.06.15
*/
public function setSize(?int $value): static {
$this->data['size'] = $value;
return $this;
}
/** /**
* Sets the MIME type * Sets the MIME type
* *
@@ -112,16 +102,6 @@ abstract class MessagePartMutableAbstract extends MessagePartBaseAbstract {
return $this; return $this;
} }
/**
* Sets the content id
*
* @since 2026.06.15
*/
public function setContentId(?string $value): static {
$this->data['cid'] = $value;
return $this;
}
/** /**
* Sets the language * Sets the language
* *
@@ -150,16 +130,6 @@ abstract class MessagePartMutableAbstract extends MessagePartBaseAbstract {
return $this; return $this;
} }
/**
* Sets the content payload
*
* @since 2026.06.15
*/
public function setContent(?string $value): static {
$this->data['content'] = $value;
return $this;
}
/** /**
* Sets the sub-parts * Sets the sub-parts
* *
@@ -10,7 +10,6 @@ declare(strict_types=1);
namespace KTXF\Mail\Object; namespace KTXF\Mail\Object;
use DateTimeImmutable; use DateTimeImmutable;
use Exception;
use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract; use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
/** /**
@@ -22,110 +21,7 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
*/ */
abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract implements MessagePropertiesBaseInterface { abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract implements MessagePropertiesBaseInterface {
protected string $type = 'mail:message'; protected string $type = 'mail.message';
protected function extractBodyContent(?MessagePartInterface $part, string $type): ?string {
if ($part === null) {
return null;
}
if ($part->getType() === $type) {
$content = $part->getContent();
return is_string($content) && $content !== '' ? $content : null;
}
foreach ($part->getParts() as $subPart) {
$content = $this->extractBodyContent($subPart, $type);
if ($content !== null) {
return $content;
}
}
return null;
}
protected function materializeAddress(mixed $value): ?AddressInterface {
if ($value instanceof AddressInterface) {
return $value;
}
if (is_string($value) && $value !== '') {
return Address::fromString($value);
}
if (!is_array($value) || $value === []) {
return null;
}
if (array_is_list($value)) {
return $this->materializeAddress($value[0] ?? null);
}
return Address::fromArray([
AddressInterface::PROPERTY_ADDRESS => $value[AddressInterface::PROPERTY_ADDRESS],
AddressInterface::PROPERTY_LABEL => $value[AddressInterface::PROPERTY_LABEL] ?? null,
]);
}
/**
* @return array<int,AddressInterface>
*/
protected function materializeAddresses(array $values): array {
$addresses = [];
foreach ($values as $value) {
$address = $this->materializeAddress($value);
if ($address !== null) {
$addresses[] = $address;
}
}
return $addresses;
}
protected function materializeDate(mixed $value): ?DateTimeImmutable {
if ($value instanceof DateTimeImmutable) {
return $value;
}
if (!is_string($value) || $value === '') {
return null;
}
try {
return new DateTimeImmutable($value);
} catch (Exception) {
return null;
}
}
protected function materializePart(mixed $value): ?MessagePartInterface {
if ($value instanceof MessagePartInterface) {
return $value;
}
if (!is_array($value) || $value === []) {
return null;
}
return MessagePart::fromArray($value);
}
/**
* @return array<int,MessagePartInterface>
*/
protected function materializeParts(array $values): array {
$parts = [];
foreach ($values as $value) {
$part = $this->materializePart($value);
if ($part !== null) {
$parts[] = $part;
}
}
return $parts;
}
/** /**
* @inheritDoc * @inheritDoc
@@ -180,56 +76,56 @@ abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract
* @inheritDoc * @inheritDoc
*/ */
public function getReceived(): ?DateTimeImmutable { public function getReceived(): ?DateTimeImmutable {
return $this->materializeDate($this->data[static::PROPERTY_RECEIVED] ?? null); return $this->data[static::PROPERTY_RECEIVED] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSent(): ?DateTimeImmutable { public function getSent(): ?DateTimeImmutable {
return $this->materializeDate($this->data[static::PROPERTY_SENT] ?? null); return $this->data[static::PROPERTY_SENT] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSender(): ?AddressInterface { public function getSender(): ?AddressInterface {
return $this->materializeAddress($this->data[static::PROPERTY_SENDER] ?? null); return $this->data[static::PROPERTY_SENDER] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getFrom(): ?AddressInterface { public function getFrom(): ?AddressInterface {
return $this->materializeAddress($this->data[static::PROPERTY_FROM] ?? null); return $this->data[static::PROPERTY_FROM] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getReplyTo(): array { public function getReplyTo(): array {
return $this->materializeAddresses($this->data[static::PROPERTY_REPLY_TO] ?? []); return $this->data[static::PROPERTY_REPLY_TO] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getTo(): array { public function getTo(): array {
return $this->materializeAddresses($this->data[static::PROPERTY_TO] ?? []); return $this->data[static::PROPERTY_TO] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getCc(): array { public function getCc(): array {
return $this->materializeAddresses($this->data[static::PROPERTY_CC] ?? []); return $this->data[static::PROPERTY_CC] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBcc(): array { public function getBcc(): array {
return $this->materializeAddresses($this->data[static::PROPERTY_BCC] ?? []); return $this->data[static::PROPERTY_BCC] ?? [];
} }
/** /**
@@ -243,38 +139,36 @@ abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract
* @inheritDoc * @inheritDoc
*/ */
public function getBody(): ?MessagePartInterface { public function getBody(): ?MessagePartInterface {
return $this->materializePart($this->data[static::PROPERTY_BODY] ?? null); return $this->data[static::PROPERTY_BODY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function hasBody(): bool { public function hasBody(): bool {
$body = $this->getBody(); return ($this->data[static::PROPERTY_BODY_TEXT_PLAIN] !== null && $this->data[static::PROPERTY_BODY_TEXT_PLAIN] !== '')
|| ($this->data[static::PROPERTY_BODY_TEXT_HTML] !== null && $this->data[static::PROPERTY_BODY_TEXT_HTML] !== '');
return $this->extractBodyContent($body, 'text/plain') !== null
|| $this->extractBodyContent($body, 'text/html') !== null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBodyTextPlain(): ?string { public function getBodyTextPlain(): ?string {
return $this->extractBodyContent($this->getBody(), 'text/plain'); return $this->data[static::PROPERTY_BODY_TEXT_PLAIN] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBodyTextHtml(): ?string { public function getBodyTextHtml(): ?string {
return $this->extractBodyContent($this->getBody(), 'text/html'); return $this->data[static::PROPERTY_BODY_TEXT_HTML] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getAttachments(): array { public function getAttachments(): array {
return $this->materializeParts($this->data[static::PROPERTY_ATTACHMENTS] ?? []); return $this->data[static::PROPERTY_ATTACHMENTS] ?? [];
} }
/** /**
@@ -282,7 +176,7 @@ abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract
*/ */
public function getFlags(): array { public function getFlags(): array {
return $this->data[static::PROPERTY_FLAGS] ?? [ return $this->data[static::PROPERTY_FLAGS] ?? [
'seen' => false, 'read' => false,
'starred' => false, 'starred' => false,
'important' => false, 'important' => false,
'answered' => false, 'answered' => false,
@@ -34,6 +34,8 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
public const PROPERTY_BCC = 'bcc'; public const PROPERTY_BCC = 'bcc';
public const PROPERTY_SUBJECT = 'subject'; public const PROPERTY_SUBJECT = 'subject';
public const PROPERTY_BODY = 'body'; public const PROPERTY_BODY = 'body';
public const PROPERTY_BODY_TEXT_PLAIN = 'bodyTextPlain';
public const PROPERTY_BODY_TEXT_HTML = 'bodyTextHtml';
public const PROPERTY_ATTACHMENTS = 'attachments'; public const PROPERTY_ATTACHMENTS = 'attachments';
public const PROPERTY_FLAGS = 'flags'; public const PROPERTY_FLAGS = 'flags';
public const PROPERTY_TAGS = 'tags'; public const PROPERTY_TAGS = 'tags';
@@ -215,7 +217,7 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @return array<int,MessagePartInterface> * @return array<int,AttachmentInterface>
*/ */
public function getAttachments(): array; public function getAttachments(): array;
@@ -10,7 +10,6 @@ declare(strict_types=1);
namespace KTXF\Mail\Object; namespace KTXF\Mail\Object;
use DateTimeImmutable; use DateTimeImmutable;
use DateTimeInterface;
/** /**
* Abstract Message Properties Mutable Class * Abstract Message Properties Mutable Class
@@ -22,90 +21,6 @@ use DateTimeInterface;
abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbstract implements MessagePropertiesMutableInterface { abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbstract implements MessagePropertiesMutableInterface {
protected string $type = 'mail.message'; protected string $type = 'mail.message';
/**
* @param array<int,AddressInterface> $values
*
* @return array<int,array<string,string|null>>
*/
protected function normalizeAddresses(array $values): array {
return array_map(
static fn(AddressInterface $value): array => $value->toArray(),
$values,
);
}
protected function normalizeDate(?DateTimeImmutable $value): ?string {
return $value?->format(DATE_ATOM);
}
/**
* @param array<int,MessagePartInterface> $values
*
* @return array<int,array<string,mixed>>
*/
protected function normalizeParts(array $values): array {
return array_map(
static fn(MessagePartInterface $value): array => $value->jsonSerialize(),
$values,
);
}
protected function buildBodyPartFromContent(?string $textPlain, ?string $textHtml): ?MessagePart {
$hasTextPlain = is_string($textPlain) && $textPlain !== '';
$hasTextHtml = is_string($textHtml) && $textHtml !== '';
if (!$hasTextPlain && !$hasTextHtml) {
return null;
}
if ($hasTextPlain && $hasTextHtml) {
return MessagePart::fromArray([
'partId' => 'body',
'type' => 'multipart/alternative',
'subParts' => [
[
'partId' => 'body.text',
'type' => 'text/plain',
'charset' => 'utf-8',
'content' => $textPlain,
'disposition' => 'inline',
],
[
'partId' => 'body.html',
'type' => 'text/html',
'charset' => 'utf-8',
'content' => $textHtml,
'disposition' => 'inline',
],
],
]);
}
return MessagePart::fromArray([
'partId' => 'body',
'type' => $hasTextHtml ? 'text/html' : 'text/plain',
'charset' => 'utf-8',
'content' => $hasTextHtml ? $textHtml : $textPlain,
'disposition' => 'inline',
]);
}
protected function updateBodyContent(string $type, ?string $value): static {
$currentPlain = $this->getBodyTextPlain();
$currentHtml = $this->getBodyTextHtml();
if ($type === 'text/plain') {
$currentPlain = $value;
} else {
$currentHtml = $value;
}
$this->data[static::PROPERTY_BODY] = $this->buildBodyPartFromContent($currentPlain, $currentHtml)?->jsonSerialize();
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
@@ -176,16 +91,16 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function setReceived(?DateTimeInterface $value): static { public function setReceived(?DateTimeImmutable $value): static {
$this->data[static::PROPERTY_RECEIVED] = $this->normalizeDate($value); $this->data[static::PROPERTY_RECEIVED] = $value;
return $this; return $this;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function setSent(?DateTimeInterface $value): static { public function setSent(DateTimeImmutable $value): static {
$this->data[static::PROPERTY_SENT] = $this->normalizeDate($value); $this->data[static::PROPERTY_SENT] = $value;
return $this; return $this;
} }
@@ -193,7 +108,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setSender(?AddressInterface $value): static { public function setSender(?AddressInterface $value): static {
$this->data[static::PROPERTY_SENDER] = $value?->toArray(); $this->data[static::PROPERTY_SENDER] = $value;
return $this; return $this;
} }
@@ -201,7 +116,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setFrom(AddressInterface $value): static { public function setFrom(AddressInterface $value): static {
$this->data[static::PROPERTY_FROM] = $value->toArray(); $this->data[static::PROPERTY_FROM] = $value;
return $this; return $this;
} }
@@ -209,7 +124,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setReplyTo(AddressInterface ...$value): static { public function setReplyTo(AddressInterface ...$value): static {
$this->data[static::PROPERTY_REPLY_TO] = $this->normalizeAddresses($value); $this->data[static::PROPERTY_REPLY_TO] = $value;
return $this; return $this;
} }
@@ -217,7 +132,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setTo(AddressInterface ...$value): static { public function setTo(AddressInterface ...$value): static {
$this->data[static::PROPERTY_TO] = $this->normalizeAddresses($value); $this->data[static::PROPERTY_TO] = $value;
return $this; return $this;
} }
@@ -225,7 +140,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setCc(AddressInterface ...$value): static { public function setCc(AddressInterface ...$value): static {
$this->data[static::PROPERTY_CC] = $this->normalizeAddresses($value); $this->data[static::PROPERTY_CC] = $value;
return $this; return $this;
} }
@@ -233,7 +148,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setBcc(AddressInterface ...$value): static { public function setBcc(AddressInterface ...$value): static {
$this->data[static::PROPERTY_BCC] = $this->normalizeAddresses($value); $this->data[static::PROPERTY_BCC] = $value;
return $this; return $this;
} }
@@ -249,7 +164,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setBody(?MessagePartInterface $value): static { public function setBody(?MessagePartInterface $value): static {
$this->data[static::PROPERTY_BODY] = $value?->jsonSerialize(); $this->data[static::PROPERTY_BODY] = $value;
return $this; return $this;
} }
@@ -257,29 +172,31 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
* @inheritDoc * @inheritDoc
*/ */
public function setBodyTextPlain(?string $value): static { public function setBodyTextPlain(?string $value): static {
return $this->updateBodyContent('text/plain', $value); $this->data[static::PROPERTY_BODY_TEXT_PLAIN] = $value;
}
/**
* @inheritDoc
*/
public function setBodyTextHtml(?string $value): static {
return $this->updateBodyContent('text/html', $value);
}
/**
* @inheritDoc
*/
public function setAttachments(\KTXF\Mail\Object\MessagePartInterface ...$value): static {
$this->data[static::PROPERTY_ATTACHMENTS] = $this->normalizeParts($value);
return $this; return $this;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function addAttachment(\KTXF\Mail\Object\MessagePartInterface $value): static { public function setBodyTextHtml(?string $value): static {
$this->data[static::PROPERTY_ATTACHMENTS][] = $value->jsonSerialize(); $this->data[static::PROPERTY_BODY_TEXT_HTML] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setAttachments(AttachmentInterface ...$value): static {
$this->data[static::PROPERTY_ATTACHMENTS] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function addAttachment(AttachmentInterface $value): static {
$this->data[static::PROPERTY_ATTACHMENTS][] = $value;
return $this; return $this;
} }
@@ -295,7 +212,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
public function setFlags(array $value): static { public function setFlags(array $value): static {
if (!isset($this->data[static::PROPERTY_FLAGS])) { if (!isset($this->data[static::PROPERTY_FLAGS])) {
$this->data[static::PROPERTY_FLAGS] = [ $this->data[static::PROPERTY_FLAGS] = [
'seen' => false, 'read' => false,
'starred' => false, 'starred' => false,
'important' => false, 'important' => false,
'answered' => false, 'answered' => false,
@@ -315,7 +232,7 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
public function setFlag(string $name, bool $value): static { public function setFlag(string $name, bool $value): static {
if (!isset($this->data[static::PROPERTY_FLAGS])) { if (!isset($this->data[static::PROPERTY_FLAGS])) {
$this->data[static::PROPERTY_FLAGS] = [ $this->data[static::PROPERTY_FLAGS] = [
'seen' => false, 'read' => false,
'starred' => false, 'starred' => false,
'important' => false, 'important' => false,
'answered' => false, 'answered' => false,
@@ -223,22 +223,22 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param MessagePartInterface ...$value * @param AttachmentInterface ...$value
* *
* @return self * @return self
*/ */
public function setAttachments(MessagePartInterface ...$value): static; public function setAttachments(AttachmentInterface ...$value): static;
/** /**
* Adds an attachment * Adds an attachment
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param MessagePartInterface $value * @param AttachmentInterface $value
* *
* @return self * @return self
*/ */
public function addAttachment(MessagePartInterface $value): static; public function addAttachment(AttachmentInterface $value): static;
/** /**
* Sets message flags * Sets message flags
@@ -13,15 +13,15 @@ use KTXF\Mail\Service\ServiceBaseInterface;
use KTXF\Resource\Provider\ResourceProviderBaseInterface; use KTXF\Resource\Provider\ResourceProviderBaseInterface;
/** /**
* Provider Base Interface * Mail Provider Base Interface
* *
* Core interface for providers with context-aware service discovery. * Core interface for mail providers with context-aware service discovery.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ProviderBaseInterface extends ResourceProviderBaseInterface{ interface ProviderBaseInterface extends ResourceProviderBaseInterface{
public const JSON_TYPE = 'mail:provider'; public const JSON_TYPE = 'mail.provider';
/** /**
* Finds a service that handles a specific email address * Finds a service that handles a specific email address
@@ -12,11 +12,11 @@ namespace KTXF\Mail\Provider;
use KTXF\Resource\Provider\ResourceServiceLocationInterface; use KTXF\Resource\Provider\ResourceServiceLocationInterface;
/** /**
* Provider Autodiscovery Interface * Mail Provider Autodiscovery Interface
* *
* Optional interface for providers that support automatic service discovery * Optional interface for mail providers that support automatic service discovery
* from email addresses or domains. Providers implementing this interface can * from email addresses or domains. Providers implementing this interface can
* discover service configurations using various methods specific to their * discover mail service configurations using various methods specific to their
* protocol or provider type. * protocol or provider type.
* *
* Examples: * Examples:
@@ -28,8 +28,6 @@ use KTXF\Resource\Provider\ResourceServiceLocationInterface;
*/ */
interface ProviderServiceDiscoverInterface { interface ProviderServiceDiscoverInterface {
public const CAPABILITY_SERVICE_DISCOVER = 'ServiceDiscover';
/** /**
* Attempts to discover service configuration using provider-specific methods. * Attempts to discover service configuration using provider-specific methods.
* *
@@ -12,9 +12,11 @@ namespace KTXF\Mail\Provider;
use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface; use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
/** /**
* Provider Service Mutate Interface * Mail Provider Service Mutate Interface
* *
* Optional interface for providers that support service CRUD operations * Optional interface for providers that support service CRUD operations.
*
* Implementations return ServiceMutableInterface instances (which extend ResourceServiceMutateInterface).
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -26,5 +28,6 @@ use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
interface ProviderServiceMutateInterface extends ResourceProviderServiceMutateInterface { interface ProviderServiceMutateInterface extends ResourceProviderServiceMutateInterface {
// Methods inherited from ResourceProviderServiceMutateInterface // Methods inherited from ResourceProviderServiceMutateInterface
// Implementations should return/accept ServiceMutableInterface instances
} }
@@ -13,20 +13,30 @@ use KTXF\Mail\Service\ServiceBaseInterface;
use KTXF\Mail\Service\ServiceMutableInterface; use KTXF\Mail\Service\ServiceMutableInterface;
/** /**
* Provider Service Test Interface * Mail Provider Service Test Interface
* *
* Optional interface for providers that support testing service connections * Optional interface for mail providers that support testing service connections.
* Providers implementing this interface can validate connection parameters,
* test authentication, and verify service availability before creating a
* persistent service configuration.
*
* Supports two testing modes:
* 1. Testing an existing service (validate current configuration)
* 2. Testing a fresh configuration (validate before saving)
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ProviderServiceTestInterface { interface ProviderServiceTestInterface {
public const CAPABILITY_SERVICE_TEST = 'ServiceTest';
/** /**
* Test a service connection * Test a service connection
* *
* Tests connectivity, authentication, and capabilities of a service * Tests connectivity, authentication, and capabilities of a service.
*
* For new services: use serviceFresh() to create a service, configure it with
* setters, then pass it to this method for testing before persisting.
*
* For existing services: fetch the service and pass it directly.
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -39,8 +49,28 @@ interface ProviderServiceTestInterface {
* *
* @return array Test results in the format: * @return array Test results in the format:
* [ * [
* 'disposition' => 'Success' | 'Failure' | 'Warning', * 'success' => bool,
* 'message' => 'Connection successful' | 'Error message', * 'message' => 'Connection successful' | 'Error message',
* 'details' => [
* 'connected' => bool, // Socket/HTTP connection succeeded
* 'authenticated' => bool, // Authentication succeeded
* 'capabilities' => ['IMAP4rev1', ...], // Server capabilities (if applicable)
* 'serverInfo' => 'Server version/banner',
* 'latency' => 123, // Connection time in milliseconds
* 'protocols' => [
* 'inbound' => [
* 'connected' => bool,
* 'authenticated' => bool,
* 'error' => 'error message if failed'
* ],
* 'outbound' => [ // For split-socket (IMAP+SMTP)
* 'connected' => bool,
* 'authenticated' => bool,
* 'error' => 'error message if failed'
* ]
* ],
* 'errors' => ['Error 1', 'Error 2'], // List of errors encountered
* ]
* ] * ]
*/ */
public function serviceTest(ServiceBaseInterface|ServiceMutableInterface $service, array $options = []): array; public function serviceTest(ServiceBaseInterface|ServiceMutableInterface $service, array $options = []): array;
@@ -11,21 +11,19 @@ namespace KTXF\Mail\Service;
use Generator; use Generator;
use KTXF\Mail\Collection\CollectionBaseInterface; use KTXF\Mail\Collection\CollectionBaseInterface;
use KTXF\Mail\Entity\EntityBaseInterface;
use KTXF\Mail\Object\AddressInterface; use KTXF\Mail\Object\AddressInterface;
use KTXF\Resource\BinaryResource;
use KTXF\Resource\Delta\Delta; use KTXF\Resource\Delta\Delta;
use KTXF\Resource\Filter\IFilter; use KTXF\Resource\Filter\IFilter;
use KTXF\Resource\Identifier\EntityIdentifierInterface;
use KTXF\Resource\Provider\ResourceServiceBaseInterface; use KTXF\Resource\Provider\ResourceServiceBaseInterface;
use KTXF\Resource\Range\IRange; use KTXF\Resource\Range\IRange;
use KTXF\Resource\Range\RangeType; use KTXF\Resource\Range\RangeType;
use KTXF\Resource\Sort\ISort; use KTXF\Resource\Sort\ISort;
/** /**
* Service Base Interface * Mail Service Base Interface
* *
* Minimum interface for a service, providing read-only access to collections and entities. * Core interface for mail services with full protocol support (IMAP, JMAP, EWS, ActiveSync, Gmail API, etc.)
* Provides identity, addressing, capability information, and collection/message operations.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -72,9 +70,9 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public const CAPABILITY_ENTITY_SORT_DATE_SENT = 'sent'; public const CAPABILITY_ENTITY_SORT_DATE_SENT = 'sent';
public const CAPABILITY_ENTITY_SORT_SIZE = 'size'; public const CAPABILITY_ENTITY_SORT_SIZE = 'size';
public const JSON_TYPE = 'mail:service'; public const JSON_TYPE = 'mail.service';
public const PROPERTY_PRIMARY_ADDRESS = 'primaryAddress'; public const JSON_PROPERTY_PRIMARY_ADDRESS = 'primaryAddress';
public const PROPERTY_SECONDARY_ADDRESSES = 'secondaryAddresses'; public const JSON_PROPERTY_SECONDARY_ADDRESSES = 'secondaryAddresses';
/** /**
* Gets the primary mailing address for this service * Gets the primary mailing address for this service
@@ -113,7 +111,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* @param IFilter|null $filter Optional filter criteria * @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order * @param ISort|null $sort Optional sort order
* *
* @return array<string|int,CollectionBaseInterface> Collections indexed by identifier * @return array<string|int,CollectionBaseInterface> Collections indexed by ID
*/ */
public function collectionList(string|int $location, ?IFilter $filter = null, ?ISort $sort = null): array; public function collectionList(string|int $location, ?IFilter $filter = null, ?ISort $sort = null): array;
@@ -140,9 +138,9 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int ...$identifiers Collection identifiers to check * @param string|int ...$identifiers Collection IDs to check
* *
* @return array<string|int,bool> Map of identifier => exists * @return array<string|int,bool> Map of ID => exists
*/ */
public function collectionExtant(string|int $location, string|int ...$identifiers): array; public function collectionExtant(string|int $location, string|int ...$identifiers): array;
@@ -151,44 +149,44 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $identifier Collection identifier * @param string|int $identifier Collection ID
* *
* @return CollectionBaseInterface|null Collection or null if not found * @return CollectionBaseInterface|null Collection or null if not found
*/ */
public function collectionFetch(string|int $identifier): ?CollectionBaseInterface; public function collectionFetch(string|int $identifier): ?CollectionBaseInterface;
/** /**
* Lists entities in a collection * Lists messages in a collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param IFilter|null $filter Optional filter criteria * @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order * @param ISort|null $sort Optional sort order
* @param IRange|null $range Optional pagination * @param IRange|null $range Optional pagination
* @param array|null $properties Optional entity properties to fetch * @param array|null $properties Optional message properties to fetch
* *
* @return array<string,EntityBaseInterface> Entities indexed by Urn * @return array<string|int,EntityBaseInterface> Messages indexed by ID
*/ */
public function entityListBulk(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array; public function entityList(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array;
/** /**
* Lists entities in a collection * Lists messages in a collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param IFilter|null $filter Optional filter criteria * @param IFilter|null $filter Optional filter criteria
* @param ISort|null $sort Optional sort order * @param ISort|null $sort Optional sort order
* @param IRange|null $range Optional pagination * @param IRange|null $range Optional pagination
* @param array|null $properties Optional entity properties to fetch * @param array|null $properties Optional message properties to fetch
* *
* @return Generator Yields entities one by one as EntityBaseInterface * @return Generator Yields messages one by one as EntityBaseInterface
*/ */
public function entityListStream(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): Generator; public function entityListStream(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): Generator;
/** /**
* Creates a filter builder for entities * Creates a filter builder for messages
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -197,7 +195,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListFilter(): IFilter; public function entityListFilter(): IFilter;
/** /**
* Creates a sort builder for entities * Creates a sort builder for messages
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -206,7 +204,7 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListSort(): ISort; public function entityListSort(): ISort;
/** /**
* Creates a range builder for entities * Creates a range builder for messages
* *
* @since 2025.05.01 * @since 2025.05.01
* *
@@ -217,60 +215,40 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
public function entityListRange(RangeType $type): IRange; public function entityListRange(RangeType $type): IRange;
/** /**
* Gets incremental changes since last signature * Gets incremental changes since last sync
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param string $signature Token from previous delta * @param string $signature Sync token from previous sync
* @param string $detail Detail level: 'ids', 'minimal', 'full'
* *
* @return array ['signature' => string, 'added' => array, 'modified' => array, 'removed' => array] * @return array ['signature' => string, 'added' => array, 'modified' => array, 'removed' => array]
*/ */
public function entityDelta(string|int $collection, string $signature): Delta; public function entityDelta(string|int $collection, string $signature, string $detail = 'ids'): Delta;
/** /**
* Checks if entities exist * Checks if messages exist
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $collection Collection identifier * @param string|int $collection Collection ID
* @param string|int ...$identifiers Entity identifiers to check * @param string|int ...$identifiers Message IDs to check
* *
* @return array<string|int,bool> Map of identifier => exists * @return array<string|int,bool> Map of ID => exists
*/ */
public function entityExtant(string|int $collection, string|int ...$identifiers): array; public function entityExtant(string|int $collection, string|int ...$identifiers): array;
/** /**
* Fetches one or more entities as an array * Fetches one or more entities
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param EntityIdentifierInterface ...$identifiers Entity identifiers to fetch * @param string|int $collection Collection ID
* @param string|int ...$identifiers Message IDs to fetch
* *
* @return array<string,EntityBaseInterface> Entities indexed by Urn * @return array<string|int,EntityBaseInterface> Messages indexed by ID
*/ */
public function entityFetchBulk(EntityIdentifierInterface ...$identifiers): array; public function entityFetch(string|int $collection, string|int ...$identifiers): array;
/**
* Fetches one or more entities as a stream
*
* @since 2025.05.01
*
* @param EntityIdentifierInterface ...$identifiers Entity identifiers to fetch
*
* @return Generator<string,EntityBaseInterface> Yields entities one by one
*/
public function entityFetchStream(EntityIdentifierInterface ...$identifiers): Generator;
/**
* Downloads an entity or part of an entity
*
* @since 2025.05.01
*
* @param EntityIdentifierInterface $target Entity identifier
* @param array|null $part Optional part to download
*
* @return BinaryResource
*/
public function entityDownload(EntityIdentifierInterface $target, array|null $part): BinaryResource;
} }
@@ -15,9 +15,10 @@ use KTXF\Mail\Collection\CollectionPropertiesBaseInterface;
use KTXF\Resource\Identifier\CollectionIdentifier; use KTXF\Resource\Identifier\CollectionIdentifier;
/** /**
* Service Collection Mutable Interface * Mail Service Collection Mutable Interface
* *
* Optional interface for services that support collection CRUD operations * Optional interface for services that support collection CRUD operations.
* Provides mailbox/folder creation, modification, deletion, and moving.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -12,9 +12,10 @@ namespace KTXF\Mail\Service;
use KTXF\Resource\Provider\ResourceServiceConfigureInterface; use KTXF\Resource\Provider\ResourceServiceConfigureInterface;
/** /**
* Service Configurable Interface * Mail Service Configurable Interface
* *
* Extends base service interface with setter methods for mutable properties * Extends base service interface with setter methods for mutable properties.
* Used for service configuration and updates.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -16,9 +16,10 @@ use KTXF\Resource\Identifier\CollectionIdentifier;
use KTXF\Resource\Identifier\EntityIdentifier; use KTXF\Resource\Identifier\EntityIdentifier;
/** /**
* Service Entity Mutable Interface * Mail Service Entity Mutable Interface
* *
* Optional interface for services that support entity CRUD operations * Optional interface for services that support entity CRUD operations.
* Provides entity creation, modification, deletion, copying, moving, and flag management.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -65,20 +66,6 @@ interface ServiceEntityMutableInterface {
*/ */
public function entityModify(EntityIdentifier $target, MessagePropertiesMutableInterface $properties): EntityBaseInterface; public function entityModify(EntityIdentifier $target, MessagePropertiesMutableInterface $properties): EntityBaseInterface;
/**
* Patches an existing entity(ies) with partial data
*
* @since 2025.05.01
*
* @param MessagePropertiesMutableInterface $properties Partial entity properties
* @param EntityIdentifier ...$targets Source entities to patch
*
* @return array<string, array{
* disposition: 'patched'|'error'
* }> Results keyed by source entity identifier
*/
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array;
/** /**
* Deletes entities * Deletes entities
* *
@@ -94,6 +81,20 @@ interface ServiceEntityMutableInterface {
*/ */
public function entityDelete(EntityIdentifier ...$targets): array; public function entityDelete(EntityIdentifier ...$targets): array;
/**
* Patches an existing entity(ies) with partial data
*
* @since 2025.05.01
*
* @param MessagePropertiesMutableInterface $properties Partial entity properties
* @param EntityIdentifier ...$targets Source entities to patch
*
* @return array<string, array{
* disposition: 'patched'|'error'
* }> Results keyed by source entity identifier
*/
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array;
/** /**
* Moves entities to another collection * Moves entities to another collection
* *
@@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Service;
use KTXF\Mail\Entity\EntityMutableInterface;
use KTXF\Mail\Object\AddressInterface;
use KTXF\Mail\Object\MessagePropertiesMutableInterface;
use KTXF\Mail\Submission\EntitySubmitResult;
use KTXF\Resource\Identifier\EntityIdentifierInterface;
/**
* Mail Service Submit Interface
*
* Interface for mail services capable of outbound submission.
* Supports submission of fresh in-memory messages and already-existing
* provider-backed drafts through a single provider-agnostic contract.
*
* @since 2026.06.07
*/
interface ServiceEntitySubmitInterface {
public const CAPABILITY_ENTITY_SUBMIT_FRESH = 'EntitySubmitFresh';
public const CAPABILITY_ENTITY_SUBMIT_DRAFT = 'EntitySubmitDraft';
/**
* Creates a fresh entity instance for composition
*
* @since 2025.05.01
*
* @return EntityMutableInterface Fresh entity object
*/
public function entityFresh(): EntityMutableInterface;
/**
* Submits an outbound message.
*
* @since 2026.06.07
*
* @param AddressInterface $sender Sender address
* @param EntityIdentifierInterface|null $source Source entity identifier
* @param MessagePropertiesMutableInterface|null $message Message properties
*
* @return EntitySubmitResult Normalized submission result
*/
public function entitySubmit(AddressInterface $sender, EntityIdentifierInterface|null $source = null, MessagePropertiesMutableInterface|null $message = null): EntitySubmitResult;
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Service;
use KTXF\Mail\Entity\EntityMutableInterface;
use KTXF\Mail\Exception\SendException;
/**
* Mail Service Transmit Interface
*
* Interface for mail services capable of transmitting outbound entities.
*
* @since 2025.05.01
*/
interface ServiceEntityTransmitInterface {
public const CAPABILITY_ENTITY_TRANSMIT = 'EntityTransmit';
/**
* Creates a fresh entity instance for composition
*
* @since 2025.05.01
*
* @return EntityMutableInterface Fresh entity object
*/
public function entityFresh(): EntityMutableInterface;
/**
* Transmits an outbound entity
*
* @since 2025.05.01
*
* @param EntityMutableInterface $entity Entity to transmit
*
* @return string Entity identifier assigned by the transport
*
* @throws SendException On delivery failure
*/
public function entitySend(EntityMutableInterface $entity): string;
}
@@ -13,9 +13,10 @@ use KTXF\Mail\Object\AddressInterface;
use KTXF\Resource\Provider\ResourceServiceMutateInterface; use KTXF\Resource\Provider\ResourceServiceMutateInterface;
/** /**
* Service Mutable Interface * Mail Service Mutable Interface
* *
* Extends base service interface with setter methods for mutable properties * Extends base service interface with setter methods for mutable properties.
* Used for service configuration and updates.
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
@@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXF\Mail\Submission;
use InvalidArgumentException;
use JsonSerializable;
use KTXF\Resource\Identifier\EntityIdentifier;
/**
* Entity Submit Result
*
* Normalized result for outbound submission.
*
* @since 2026.06.07
*/
final class EntitySubmitResult implements JsonSerializable {
public const DISPOSITION_SENT = 'sent';
public const DISPOSITION_ERROR = 'error';
public function __construct(
public readonly string $disposition,
public readonly ?string $transportId = null,
public readonly ?EntityIdentifier $sourceDraft = null,
public readonly ?EntityIdentifier $sentEntity = null,
public readonly ?string $errorCode = null,
public readonly ?string $errorMessage = null,
) {
if (!in_array($this->disposition, [self::DISPOSITION_SENT, self::DISPOSITION_ERROR], true)) {
throw new InvalidArgumentException('Invalid submission disposition: ' . $this->disposition);
}
}
public function jsonSerialize(): array {
return array_filter([
'disposition' => $this->disposition,
'transportId' => $this->transportId,
'sourceDraft' => $this->sourceDraft !== null ? (string)$this->sourceDraft : null,
'sentEntity' => $this->sentEntity !== null ? (string)$this->sentEntity : null,
'errorCode' => $this->errorCode,
'errorMessage' => $this->errorMessage,
], static fn(mixed $value): bool => $value !== null);
}
}
@@ -41,7 +41,7 @@ abstract class CollectionMutableAbstract extends NodeMutableAbstract implements
// Copy all property values // Copy all property values
$this->properties->setLabel($value->getLabel()); $this->properties->setLabel($value->getLabel());
$this->properties->setDescription($value->getDescription()); $this->properties->setDescription($value->getDescription());
$this->properties->setRank($value->getRank()); $this->properties->setPriority($value->getPriority());
$this->properties->setVisibility($value->getVisibility()); $this->properties->setVisibility($value->getVisibility());
$this->properties->setColor($value->getColor()); $this->properties->setColor($value->getColor());
@@ -20,15 +20,17 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
*/ */
abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface { abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface {
public const JSON_TYPE = CollectionPropertiesBaseInterface::JSON_TYPE;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function content(): array { public function content(): array {
$content = $this->data[self::PROPERTY_CONTENT] ?? null; $content = $this->data[self::JSON_PROPERTY_CONTENT] ?? null;
if (is_array($content)) { if (is_array($content)) {
return array_filter(array_map(function ($item) { return array_map(function ($item) {
return $item instanceof CollectionContent ? $item : CollectionContent::tryFrom($item); return new CollectionContent($item);
}, $content)); }, $content);
} else { } else {
return []; return [];
} }
@@ -38,35 +40,35 @@ abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstra
* @inheritDoc * @inheritDoc
*/ */
public function getLabel(): string { public function getLabel(): string {
return $this->data[self::PROPERTY_LABEL] ?? ''; return $this->data[self::JSON_PROPERTY_LABEL] ?? '';
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getDescription(): ?string { public function getDescription(): ?string {
return $this->data[self::PROPERTY_DESCRIPTION] ?? null; return $this->data[self::JSON_PROPERTY_DESCRIPTION] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getRank(): ?int { public function getPriority(): ?int {
return $this->data[self::PROPERTY_RANK] ?? null; return $this->data[self::JSON_PROPERTY_PRIORITY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getVisibility(): ?bool { public function getVisibility(): ?bool {
return $this->data[self::PROPERTY_VISIBILITY] ?? null; return $this->data[self::JSON_PROPERTY_VISIBILITY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getColor(): ?string { public function getColor(): ?string {
return $this->data[self::PROPERTY_COLOR] ?? null; return $this->data[self::JSON_PROPERTY_COLOR] ?? null;
} }
} }
@@ -10,17 +10,18 @@ declare(strict_types=1);
namespace KTXF\People\Collection; namespace KTXF\People\Collection;
use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface; use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
use PhpParser\Node\Expr\Array_;
interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface { interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'people:collection'; public const JSON_TYPE = 'people:collection';
public const PROPERTY_CONTENT = 'content'; public const JSON_PROPERTY_CONTENT = 'content';
public const PROPERTY_LABEL = 'label'; public const JSON_PROPERTY_LABEL = 'label';
public const PROPERTY_DESCRIPTION = 'description'; public const JSON_PROPERTY_DESCRIPTION = 'description';
public const PROPERTY_RANK = 'rank'; public const JSON_PROPERTY_PRIORITY = 'priority';
public const PROPERTY_VISIBILITY = 'visibility'; public const JSON_PROPERTY_VISIBILITY = 'visibility';
public const PROPERTY_COLOR = 'color'; public const JSON_PROPERTY_COLOR = 'color';
/** /**
* Gets the content type of this collection * Gets the content type of this collection
@@ -46,11 +47,11 @@ interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface
public function getDescription(): ?string; public function getDescription(): ?string;
/** /**
* Gets the rank of this collection * Gets the priority of this collection
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
public function getRank(): ?int; public function getPriority(): ?int;
/** /**
* Gets the visibility of this collection * Gets the visibility of this collection
@@ -33,7 +33,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setLabel(string $value): static { public function setLabel(string $value): static {
$this->data[self::PROPERTY_LABEL] = $value; $this->data[self::JSON_PROPERTY_LABEL] = $value;
return $this; return $this;
} }
@@ -41,15 +41,15 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setDescription(?string $value): static { public function setDescription(?string $value): static {
$this->data[self::PROPERTY_DESCRIPTION] = $value; $this->data[self::JSON_PROPERTY_DESCRIPTION] = $value;
return $this; return $this;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function setRank(?int $value): static { public function setPriority(?int $value): static {
$this->data[self::PROPERTY_RANK] = $value; $this->data[self::JSON_PROPERTY_PRIORITY] = $value;
return $this; return $this;
} }
@@ -57,7 +57,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setVisibility(?bool $value): static { public function setVisibility(?bool $value): static {
$this->data[self::PROPERTY_VISIBILITY] = $value; $this->data[self::JSON_PROPERTY_VISIBILITY] = $value;
return $this; return $this;
} }
@@ -65,7 +65,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setColor(?string $value): static { public function setColor(?string $value): static {
$this->data[self::PROPERTY_COLOR] = $value; $this->data[self::JSON_PROPERTY_COLOR] = $value;
return $this; return $this;
} }
@@ -30,11 +30,11 @@ interface CollectionPropertiesMutableInterface extends NodePropertiesMutableInte
public function setDescription(?string $value): static; public function setDescription(?string $value): static;
/** /**
* Sets the rank of this collection * Sets the priority of this collection
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
public function setRank(?int $value): static; public function setPriority(?int $value): static;
/** /**
* Sets the visibility of this collection * Sets the visibility of this collection
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace KTXF\People\Entity; namespace KTXF\People\Entity;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeBaseAbstract; use KTXF\Resource\Provider\Node\NodeBaseAbstract;
/** /**
@@ -21,12 +20,7 @@ use KTXF\Resource\Provider\Node\NodeBaseAbstract;
*/ */
abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface { abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface {
protected string $type = 'people:entity'; protected EntityPropertiesBaseAbstract $properties;
protected EntityPropertiesBaseInterface $properties;
protected function nodeIdentifier(): EntityIdentifier {
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], $this->data[static::PROPERTY_COLLECTION], $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
@@ -13,6 +13,8 @@ use KTXF\Resource\Provider\Node\NodeBaseInterface;
interface EntityBaseInterface extends NodeBaseInterface { interface EntityBaseInterface extends NodeBaseInterface {
public const JSON_TYPE = 'people:entity';
/** /**
* Gets the entity properties * Gets the entity properties
* *
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace KTXF\People\Entity; namespace KTXF\People\Entity;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeMutableAbstract; use KTXF\Resource\Provider\Node\NodeMutableAbstract;
use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface; use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
@@ -22,12 +21,9 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
*/ */
abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface { abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface {
protected string $type = 'people:entity'; public const JSON_TYPE = EntityMutableInterface::JSON_TYPE;
protected EntityPropertiesMutableInterface $properties;
protected function nodeIdentifier(): EntityIdentifier { protected EntityPropertiesMutableAbstract $properties;
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], (string) $this->data[static::PROPERTY_COLLECTION], (string) $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
@@ -44,7 +40,7 @@ abstract class EntityMutableAbstract extends NodeMutableAbstract implements Enti
throw new \InvalidArgumentException('Properties must implement EntityPropertiesMutableInterface'); throw new \InvalidArgumentException('Properties must implement EntityPropertiesMutableInterface');
} }
$this->properties = $value; $this->properties->setDataRaw($value->getDataRaw());
return $this; return $this;
} }
@@ -16,6 +16,8 @@ use KTXF\Resource\Provider\Node\NodeMutableInterface;
*/ */
interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface { interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface {
public const JSON_TYPE = EntityBaseInterface::JSON_TYPE;
/** /**
* Gets the entity properties (mutable) * Gets the entity properties (mutable)
* *
@@ -13,10 +13,9 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
abstract class EntityPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements EntityPropertiesBaseInterface { abstract class EntityPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements EntityPropertiesBaseInterface {
/** public const JSON_TYPE = EntityPropertiesBaseInterface::JSON_TYPE;
* @inheritDoc
*/
public function getDataRaw(): array|string|null { public function getDataRaw(): array|string|null {
return $this->data[self::PROPERTY_DATA] ?? null; return $this->data[self::JSON_PROPERTY_DATA] ?? null;
} }
} }
@@ -14,7 +14,7 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
interface EntityPropertiesBaseInterface extends NodePropertiesBaseInterface { interface EntityPropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'people:entity'; public const JSON_TYPE = 'people:entity';
public const PROPERTY_DATA = 'data'; public const JSON_PROPERTY_DATA = 'data';
public function getDataRaw(): array|string|null; public function getDataRaw(): array|string|null;

Some files were not shown because too many files have changed in this diff Show More