diff --git a/src/bundle/ApiPlatform/Head.php b/src/bundle/ApiPlatform/Head.php
new file mode 100644
index 000000000..73698f7ad
--- /dev/null
+++ b/src/bundle/ApiPlatform/Head.php
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.json.example b/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.json.example
new file mode 100644
index 000000000..ca99248ef
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.json.example
@@ -0,0 +1,254 @@
+{
+ "BookmarkList": {
+ "_media-type": "application/vnd.ibexa.api.BookmarkList+json",
+ "count": 3,
+ "items": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Bookmark+json",
+ "__href": "/api/ibexa/v2/bookmark/65",
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57/65",
+ "id": 65,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57"
+ },
+ "pathString": "/1/2/57/65/",
+ "depth": 3,
+ "childCount": 0,
+ "remoteId": "aa538e305aea472eb221ce23d1cc4b50",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57/65/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/63"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57/65/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/63",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/63",
+ "_remoteId": "211e99934c8fef5900e4813b96ec5c87",
+ "_id": 63,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "Name": "Art3",
+ "TranslatedName": "Art3",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/63/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/63/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/63/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:34:17+00:00",
+ "publishedDate": "2021-06-28T11:34:17+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": false,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/63/objectstates"
+ }
+ }
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Bookmark+json",
+ "__href": "/api/ibexa/v2/bookmark/68",
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/68",
+ "id": 68,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58"
+ },
+ "pathString": "/1/2/58/68/",
+ "depth": 3,
+ "childCount": 0,
+ "remoteId": "b8cc4627dbc3ca693c85b6b06a8f7492",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/68/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/67"
+ },
+ "sortField": "PUBLISHED",
+ "sortOrder": "DESC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/68/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/67",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/67",
+ "_remoteId": "180adb876af5755d65c1a362fcd619c8",
+ "_id": 67,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/45"
+ },
+ "Name": "Tip1",
+ "TranslatedName": "Tip1",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/67/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/67/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/67/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:36:21+00:00",
+ "publishedDate": "2021-06-28T11:36:21+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/67/objectstates"
+ }
+ }
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Bookmark+json",
+ "__href": "/api/ibexa/v2/bookmark/59",
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59",
+ "id": 59,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "pathString": "/1/2/59/",
+ "depth": 2,
+ "childCount": 3,
+ "remoteId": "fd949fc2eed1fff847d73021ff1a6ea9",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/58"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/58",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/58",
+ "_remoteId": "00b513aae54036a16e00fb3365c4b5f3",
+ "_id": 58,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "Dog Breed Catalog",
+ "TranslatedName": "Dog Breed Catalog",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/58/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/58/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/58/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:23:10+00:00",
+ "publishedDate": "2021-06-28T11:23:10+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/58/objectstates"
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.xml.example b/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.xml.example
new file mode 100644
index 000000000..627155bff
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.xml.example
@@ -0,0 +1,121 @@
+
+
+ 3
+
+
+ 65
+ 0
+ false
+ false
+ false
+
+ /1/2/57/65/
+ 3
+ 0
+ aa538e305aea472eb221ce23d1cc4b50
+
+
+ PATH
+ ASC
+
+
+
+
+ Art3
+ Art3
+
+
+
+
+
+ 2021-06-28T11:34:17+00:00
+ 2021-06-28T11:34:17+00:00
+ eng-GB
+ 1
+ false
+ false
+ PUBLISHED
+
+
+
+
+
+
+
+ 68
+ 0
+ false
+ false
+ false
+
+ /1/2/58/68/
+ 3
+ 0
+ b8cc4627dbc3ca693c85b6b06a8f7492
+
+
+ PUBLISHED
+ DESC
+
+
+
+
+ Tip1
+ Tip1
+
+
+
+
+
+ 2021-06-28T11:36:21+00:00
+ 2021-06-28T11:36:21+00:00
+ eng-GB
+ 1
+ true
+ false
+ PUBLISHED
+
+
+
+
+
+
+
+ 59
+ 0
+ false
+ false
+ false
+
+ /1/2/59/
+ 2
+ 3
+ fd949fc2eed1fff847d73021ff1a6ea9
+
+
+ PATH
+ ASC
+
+
+
+
+ Dog Breed Catalog
+ Dog Breed Catalog
+
+
+
+
+
+ 2021-06-28T11:23:10+00:00
+ 2021-06-28T11:23:10+00:00
+ eng-GB
+ 1
+ true
+ false
+ PUBLISHED
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/assets/images/assetId/assetSource/GET/Asset.xml.example b/src/bundle/Resources/api_platform/examples/content/assets/images/assetId/assetSource/GET/Asset.xml.example
new file mode 100644
index 000000000..e3dfbbc47
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/assets/images/assetId/assetSource/GET/Asset.xml.example
@@ -0,0 +1,15 @@
+
+
+ https://images.unsplash.com/photo-1544568100-847a948585b9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1MDk5MH0
+ UtrE5DcgEyg
+ unsplash
+
+ medium-coated brown dog during daytime
+ 5184
+ 3888
+ 2018-12-11T17:46:12-05:00
+ 2020-10-23T23:08:44-04:00
+ Jamie Street
+ https://unsplash.com/@jamie452?utm_source=Ibexa+Platform+DAM+Connector&utm_medium=referral&utm_campaign=api-credit
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/binary/images/image_id/variations/variation_identifier/GET/ImageVariation.xml.example b/src/bundle/Resources/api_platform/examples/content/binary/images/image_id/variations/variation_identifier/GET/ImageVariation.xml.example
new file mode 100644
index 000000000..b9455ea03
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/binary/images/image_id/variations/variation_identifier/GET/ImageVariation.xml.example
@@ -0,0 +1,8 @@
+
+
+ http://127.0.0.1:8000/var/site/storage/images/_aliases/large/6/1/2/0/216-1-eng-GB/ez-logo-small.png
+ image/png
+ 20
+ 20
+ 1709
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.json.example b/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.json.example
new file mode 100644
index 000000000..387248e5b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.json.example
@@ -0,0 +1,80 @@
+{
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58",
+ "id": 58,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "pathString": "/1/2/58/",
+ "depth": 2,
+ "childCount": 3,
+ "remoteId": "0cfe62f27753448d79aaa8acd8d01699",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/57"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/57",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/57",
+ "_remoteId": "782f5afa9d6587804daa911e88ff5bb9",
+ "_id": 57,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "All Tips",
+ "TranslatedName": "All Tips",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/57/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:22:52+00:00",
+ "publishedDate": "2021-06-28T11:22:52+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/57/objectstates"
+ }
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.xml.example
new file mode 100644
index 000000000..d3401621c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/GET/LocationList.xml.example
@@ -0,0 +1,38 @@
+
+
+ 58
+ 0
+ false
+ false
+ false
+
+ /1/2/58/
+ 2
+ 3
+ 0cfe62f27753448d79aaa8acd8d01699
+
+
+ PATH
+ ASC
+
+
+
+
+ All Tips
+ All Tips
+
+
+
+
+
+ 2021-06-28T11:22:52+00:00
+ 2021-06-28T11:22:52+00:00
+ eng-GB
+ 1
+ true
+ false
+ PUBLISHED
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.json.example b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.json.example
new file mode 100644
index 000000000..e7bff475d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.json.example
@@ -0,0 +1,80 @@
+{
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59",
+ "id": 59,
+ "priority": 3,
+ "hidden": true,
+ "invisible": true,
+ "explicitlyHidden": true,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "pathString": "/1/2/59/",
+ "depth": 2,
+ "childCount": 5,
+ "remoteId": "remoteId-qwert999",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/58"
+ },
+ "sortField": "NAME",
+ "sortOrder": "DESC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/58",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/58",
+ "_remoteId": "00b513aae54036a16e00fb3365c4b5f3",
+ "_id": 58,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "Dog Breed Catalog",
+ "TranslatedName": "Dog Breed Catalog",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/58/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/58/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/58/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:23:10+00:00",
+ "publishedDate": "2021-06-28T11:23:10+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/58/objectstates"
+ }
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.xml.example
new file mode 100644
index 000000000..d3401621c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/Location.xml.example
@@ -0,0 +1,38 @@
+
+
+ 58
+ 0
+ false
+ false
+ false
+
+ /1/2/58/
+ 2
+ 3
+ 0cfe62f27753448d79aaa8acd8d01699
+
+
+ PATH
+ ASC
+
+
+
+
+ All Tips
+ All Tips
+
+
+
+
+
+ 2021-06-28T11:22:52+00:00
+ 2021-06-28T11:22:52+00:00
+ eng-GB
+ 1
+ true
+ false
+ PUBLISHED
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.json.example b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.json.example
new file mode 100644
index 000000000..e7a29a87a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.json.example
@@ -0,0 +1,9 @@
+{
+ "LocationUpdate": {
+ "priority": "3",
+ "hidden": true,
+ "remoteId": "remoteId-qwert999",
+ "sortField": "NAME",
+ "sortOrder": "DESC"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.xml.example
new file mode 100644
index 000000000..c4ffb31f0
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.xml.example
@@ -0,0 +1,8 @@
+
+
+ 3
+ true
+ remoteId-qwert999
+ CLASS
+ DESC
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.json.example b/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.json.example
new file mode 100644
index 000000000..387248e5b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.json.example
@@ -0,0 +1,80 @@
+{
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58",
+ "id": 58,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "pathString": "/1/2/58/",
+ "depth": 2,
+ "childCount": 3,
+ "remoteId": "0cfe62f27753448d79aaa8acd8d01699",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/57"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/58/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/57",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/57",
+ "_remoteId": "782f5afa9d6587804daa911e88ff5bb9",
+ "_id": 57,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "All Tips",
+ "TranslatedName": "All Tips",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/57/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:22:52+00:00",
+ "publishedDate": "2021-06-28T11:22:52+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/57/objectstates"
+ }
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.xml.example
new file mode 100644
index 000000000..f45e159a5
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/path/GET/Location.xml.example
@@ -0,0 +1,34 @@
+
+
+ 61
+ 0
+ false
+ false
+
+ /1/2/61/
+ 2
+ 0
+ 2cfa66027e3806b113d994c9c26d3a66
+
+
+ NAME
+ ASC
+
+
+
+
+ 666
+
+
+
+
+
+ 2018-11-09T14:49:52+01:00
+ 2018-11-09T14:49:52+01:00
+ eng-GB
+ 1
+ false
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/path/children/GET/LocationList.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/path/children/GET/LocationList.xml.example
new file mode 100644
index 000000000..82e59109a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/path/children/GET/LocationList.xml.example
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/locations/path/urlaliases/GET/UrlAliasRefList.xml.example b/src/bundle/Resources/api_platform/examples/content/locations/path/urlaliases/GET/UrlAliasRefList.xml.example
new file mode 100644
index 000000000..26a02c360
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/locations/path/urlaliases/GET/UrlAliasRefList.xml.example
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.json.example b/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.json.example
new file mode 100644
index 000000000..5e8bd68f3
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.json.example
@@ -0,0 +1,153 @@
+{
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/109",
+ "_remoteId": "8716f007ba15f6f35139acb55e39b811",
+ "_id": 109,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "Name": "draft article",
+ "TranslatedName": "draft article",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/109/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/109/currentversion",
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/109/versions/1",
+ "VersionInfo": {
+ "id": 587,
+ "versionNo": 1,
+ "status": "DRAFT",
+ "modificationDate": "2023-05-24T06:27:54+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2023-05-24T06:27:54+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "draft article"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/109"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 488,
+ "fieldDefinitionIdentifier": "title",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "draft article"
+ },
+ {
+ "id": 489,
+ "fieldDefinitionIdentifier": "short_title",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 490,
+ "fieldDefinitionIdentifier": "author",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezauthor",
+ "fieldValue": []
+ },
+ {
+ "id": 491,
+ "fieldDefinitionIdentifier": "intro",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 492,
+ "fieldDefinitionIdentifier": "body",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 493,
+ "fieldDefinitionIdentifier": "enable_comments",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezboolean",
+ "fieldValue": false
+ },
+ {
+ "id": 494,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezobjectrelation",
+ "fieldValue": {
+ "destinationContentId": null
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/109/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/placeholder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/109/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "DRAFT",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/109/objectstates"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.xml.example
new file mode 100644
index 000000000..35f5cbb16
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/POST/Content.xml.example
@@ -0,0 +1,113 @@
+
+
+
+ draft article
+ draft article
+
+
+
+
+ 586
+ 1
+ DRAFT
+ 2023-05-24T06:24:46+00:00
+
+ 2023-05-24T06:24:46+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ draft article
+
+
+
+
+
+ 481
+ title
+ eng-GB
+ ezstring
+ draft article
+
+
+ 482
+ short_title
+ eng-GB
+ ezstring
+
+
+
+ 483
+ author
+ eng-GB
+ ezauthor
+
+
+
+ 484
+ intro
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ibexa.co/xmlns/dxp/docbook/xhtml" xmlns:ezcustom="http://ibexa.co/xmlns/dxp/docbook/custom" version="5.0-variant ezpublish-1.0"><para>draft draft</para></section>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"><p>draft draft</p></section>
+
+
+
+
+ 485
+ body
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ibexa.co/xmlns/dxp/docbook/xhtml" xmlns:ezcustom="http://ibexa.co/xmlns/dxp/docbook/custom" version="5.0-variant ezpublish-1.0"><para>draft draft draft</para></section>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"><p>draft draft draft</p></section>
+
+
+
+
+ 486
+ enable_comments
+ eng-GB
+ ezboolean
+ false
+
+
+ 487
+ image
+ eng-GB
+ ezobjectrelation
+
+
+
+
+
+
+
+ /placeholder
+
+
+ image/svg+xml
+
+
+
+
+
+
+ eng-GB
+ 1
+ true
+ false
+ DRAFT
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.json.example b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.json.example
new file mode 100644
index 000000000..97f903c01
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.json.example
@@ -0,0 +1,49 @@
+{
+ "ContentCreate": {
+ "ContentType": {
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "mainLanguageCode": "eng-GB",
+ "LocationCreate": {
+ "_media-type": "application/vnd.ibexa.api.LocationCreate",
+ "ParentLocation": {
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "priority": "0",
+ "hidden": "false",
+ "sortField": "PATH",
+ "sortOrder": "ASC"
+ },
+ "Section": {
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "alwaysAvailable": "true",
+ "fields": {
+ "field": [
+ {
+ "fieldDefinitionIdentifier": "title",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "draft article"
+ },
+ {
+ "fieldDefinitionIdentifier": "intro",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue":
+ {
+ "xml": ""
+ }
+ },
+ {
+ "fieldDefinitionIdentifier": "body",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": ""
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.xml.example
new file mode 100644
index 000000000..08c966645
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.xml.example
@@ -0,0 +1,36 @@
+
+
+
+ eng-GB
+
+
+ 0
+ false
+ PATH
+ ASC
+
+
+ true
+
+
+
+ title
+ eng-GB
+ draft article
+
+
+ intro
+ eng-GB
+
+ draft draft
]]>
+
+
+
+ body
+ eng-GB
+
+ draft draft draft
]]>
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentInfo.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentInfo.xml.example
new file mode 100644
index 000000000..88ae84b8c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/POST/ContentInfo.xml.example
@@ -0,0 +1,17 @@
+
+
+
+ draft article
+ draft article
+
+
+
+
+
+ eng-GB
+ 1
+ true
+ false
+ DRAFT
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.json.example
new file mode 100644
index 000000000..0384cebbc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.json.example
@@ -0,0 +1,136 @@
+{
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/54",
+ "_remoteId": "9e863fbb0fb835ce050032b4f00de61d",
+ "_id": 54,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "Forms",
+ "TranslatedName": "Forms",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/54/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/54/currentversion",
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/54/versions/1",
+ "VersionInfo": {
+ "id": 514,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2018-09-17T06:48:13+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2018-09-17T06:48:13+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Forms"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/54"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 249,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Forms"
+ },
+ {
+ "id": 250,
+ "fieldDefinitionIdentifier": "short_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 251,
+ "fieldDefinitionIdentifier": "short_description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 252,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/54/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#folder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/6"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/55"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/54/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2018-09-17T06:48:13+00:00",
+ "publishedDate": "2018-09-17T06:48:13+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": false,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/54/objectstates"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.xml.example
new file mode 100644
index 000000000..bf3dcdccb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.xml.example
@@ -0,0 +1,93 @@
+
+
+
+ Forms
+ Forms
+
+
+
+
+ 514
+ 1
+ PUBLISHED
+ 2018-09-17T06:48:13+00:00
+
+ 2018-09-17T06:48:13+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Forms
+
+
+
+
+
+ 249
+ name
+ eng-GB
+ ezstring
+ Forms
+
+
+ 250
+ short_name
+ eng-GB
+ ezstring
+
+
+
+ 251
+ short_description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+ 252
+ description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#folder
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+ 2018-09-17T06:48:13+00:00
+ 2018-09-17T06:48:13+00:00
+ eng-GB
+ 1
+ false
+ false
+ PUBLISHED
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/ContentInfo.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/GET/ContentInfo.xml.example
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example
new file mode 100644
index 000000000..202e2149d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example
@@ -0,0 +1,17 @@
+
+
+
+ article1
+
+
+
+
+
+
+ 2019-02-19T15:00:34+01:00
+ 2019-02-19T15:00:34+01:00
+ eng-GB
+ 1
+ false
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentUpdate.xml.example
new file mode 100644
index 000000000..1388ba5ab
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentUpdate.xml.example
@@ -0,0 +1,9 @@
+
+
+ eng-GB
+
+
+
+ false
+ 69848aeb86164c35e5c98202eebe9e05
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.json.example
new file mode 100644
index 000000000..434f069a2
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.json.example
@@ -0,0 +1,89 @@
+{
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/5",
+ "VersionInfo": {
+ "id": 581,
+ "versionNo": 5,
+ "status": "DRAFT",
+ "modificationDate": "2023-05-24T06:09:49+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2023-05-24T06:09:49+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Features"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/107"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 477,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Features"
+ },
+ {
+ "id": 478,
+ "fieldDefinitionIdentifier": "short_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 479,
+ "fieldDefinitionIdentifier": "short_description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 480,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/5/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/placeholder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.xml.example
new file mode 100644
index 000000000..d6cb4c486
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/COPY/Version.xml.example
@@ -0,0 +1,73 @@
+
+
+
+ 580
+ 4
+ DRAFT
+ 2023-05-24T06:08:47+00:00
+
+ 2023-05-24T06:08:47+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Features
+
+
+
+
+
+ 477
+ name
+ eng-GB
+ ezstring
+ Features
+
+
+ 478
+ short_name
+ eng-GB
+ ezstring
+
+
+
+ 479
+ short_description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+ 480
+ description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+
+
+ /placeholder
+
+
+ image/svg+xml
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.json.example
new file mode 100644
index 000000000..a37da599d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.json.example
@@ -0,0 +1,89 @@
+{
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/2",
+ "VersionInfo": {
+ "id": 578,
+ "versionNo": 2,
+ "status": "PUBLISHED",
+ "modificationDate": "2023-05-24T05:59:09+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2023-05-24T05:59:02+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Features"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/107"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 477,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Features"
+ },
+ {
+ "id": 478,
+ "fieldDefinitionIdentifier": "short_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 479,
+ "fieldDefinitionIdentifier": "short_description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 480,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/2/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/placeholder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.xml.example
new file mode 100644
index 000000000..585f91f91
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/currentversion/GET/Version.xml.example
@@ -0,0 +1,73 @@
+
+
+
+ 578
+ 2
+ PUBLISHED
+ 2023-05-24T05:59:09+00:00
+
+ 2023-05-24T05:59:02+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Features
+
+
+
+
+
+ 477
+ name
+ eng-GB
+ ezstring
+ Features
+
+
+ 478
+ short_name
+ eng-GB
+ ezstring
+
+
+
+ 479
+ short_description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+ 480
+ description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+
+
+ /placeholder
+
+
+ image/svg+xml
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.json.example
new file mode 100644
index 000000000..20280fba5
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.json.example
@@ -0,0 +1,12 @@
+{
+ "LocationList": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/63/locations",
+ "Location": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57/65"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.xml.example
new file mode 100644
index 000000000..77e1c81c4
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example
new file mode 100644
index 000000000..06e2720ae
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example
@@ -0,0 +1,80 @@
+{
+ "Location": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/114",
+ "id": 114,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "explicitlyHidden": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59"
+ },
+ "pathString": "/1/2/59/114/",
+ "depth": 3,
+ "childCount": 0,
+ "remoteId": "47a1e4ee082fb64e93a822dcfe3a5614",
+ "Children": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/114/children"
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/59"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "UrlAliases": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/59/114/urlaliases"
+ },
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/59",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/59",
+ "_remoteId": "0fe1b1543f886b0becd4d9b2c7c517d0",
+ "_id": 59,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "Name": "Art1",
+ "TranslatedName": "Art1",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/59/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/59/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/59/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-06-28T11:33:01+00:00",
+ "publishedDate": "2021-06-28T11:33:01+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": false,
+ "isHidden": false,
+ "status": "PUBLISHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/59/objectstates"
+ }
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example
new file mode 100644
index 000000000..99fa70128
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example
@@ -0,0 +1,38 @@
+
+
+ 96
+ 0
+ false
+ true
+ false
+
+ /1/2/42/96/
+ 3
+ 0
+ 58133c8c75230e5debe362a28b92d27a
+
+
+ PATH
+ ASC
+
+
+
+
+ Art3
+ Art3
+
+
+
+
+
+ 2021-06-28T11:34:17+00:00
+ 2021-06-28T11:34:17+00:00
+ eng-GB
+ 1
+ false
+ false
+ PUBLISHED
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.json.example
new file mode 100644
index 000000000..44d6271ad
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.json.example
@@ -0,0 +1,12 @@
+{
+ "LocationCreate": {
+ "_media-type": "application/vnd.ibexa.api.LocationCreate",
+ "ParentLocation": {
+ "_href": "/api/ibexa/v2/content/locations/1/59"
+ },
+ "priority": "0",
+ "hidden": false,
+ "sortField": "PATH",
+ "sortOrder": "ASC"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.xml.example
new file mode 100644
index 000000000..9686bfc0d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.xml.example
@@ -0,0 +1,8 @@
+
+
+
+ 0
+ false
+ PATH
+ ASC
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example
new file mode 100644
index 000000000..4e8035e60
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example
@@ -0,0 +1,23 @@
+{
+ "ContentObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "ObjectState": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates/1"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/3/objectstates/3"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7/objectstates/7"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/8/objectstates/8"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.xml.example
new file mode 100644
index 000000000..f6533987f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.xml.example
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.json.example
new file mode 100644
index 000000000..6c847b4d9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.json.example
@@ -0,0 +1,9 @@
+{
+ "ContentObjectStates": {
+ "ObjectState": [
+ {
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates/2"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.xml.example
new file mode 100644
index 000000000..086a32de7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.request.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.json.example
new file mode 100644
index 000000000..87c9b1709
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.json.example
@@ -0,0 +1,11 @@
+{
+ "ContentObjectStates": {
+ "_media-type": "application\/vnd.ibexa.api.ContentObjectStates+json",
+ "ObjectState": [
+ {
+ "_media-type": "application\/vnd.ibexa.api.ObjectState+json",
+ "_href": "\/api\/ibexa\/v2\/content\/objectstategroups\/2\/objectstates\/2"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example
new file mode 100644
index 000000000..2cdc2305a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.json.example
new file mode 100644
index 000000000..3c042e954
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.json.example
@@ -0,0 +1,125 @@
+{
+ "VersionList": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/61/versions",
+ "VersionItem": [
+ {
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/61/versions/1"
+ },
+ "VersionInfo": {
+ "id": 521,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2021-06-28T11:33:49+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-06-28T11:33:31+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Art1"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/61"
+ }
+ }
+ },
+ {
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/61/versions/2"
+ },
+ "VersionInfo": {
+ "id": 580,
+ "versionNo": 2,
+ "status": "DRAFT",
+ "modificationDate": "2021-07-26T08:10:02+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-07-26T08:10:02+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Art1"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/61"
+ }
+ }
+ },
+ {
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/61/versions/3"
+ },
+ "VersionInfo": {
+ "id": 581,
+ "versionNo": 3,
+ "status": "DRAFT",
+ "modificationDate": "2021-07-26T08:16:50+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-07-26T08:16:50+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Art1"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/61"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.xml.example
new file mode 100644
index 000000000..ca94eaf9e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.xml.example
@@ -0,0 +1,69 @@
+
+
+
+
+
+ 521
+ 1
+ PUBLISHED
+ 2021-06-28T11:33:49+00:00
+
+ 2021-06-28T11:33:31+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Art1
+
+
+
+
+
+
+
+ 580
+ 2
+ DRAFT
+ 2021-07-26T08:10:02+00:00
+
+ 2021-07-26T08:10:02+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Art1
+
+
+
+
+
+
+
+ 581
+ 3
+ DRAFT
+ 2021-07-26T08:16:50+00:00
+
+ 2021-07-26T08:16:50+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Art1
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.json.example
new file mode 100644
index 000000000..580dc2315
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.json.example
@@ -0,0 +1,89 @@
+{
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/8",
+ "VersionInfo": {
+ "id": 584,
+ "versionNo": 8,
+ "status": "DRAFT",
+ "modificationDate": "2023-05-24T06:14:07+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2023-05-24T06:14:07+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Features"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/107"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 477,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Features"
+ },
+ {
+ "id": 478,
+ "fieldDefinitionIdentifier": "short_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 479,
+ "fieldDefinitionIdentifier": "short_description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 480,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/8/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/placeholder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.xml.example
new file mode 100644
index 000000000..b04721156
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/COPY/Version.xml.example
@@ -0,0 +1,73 @@
+
+
+
+ 583
+ 7
+ DRAFT
+ 2023-05-24T06:13:50+00:00
+
+ 2023-05-24T06:13:50+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Features
+
+
+
+
+
+ 477
+ name
+ eng-GB
+ ezstring
+ Features
+
+
+ 478
+ short_name
+ eng-GB
+ ezstring
+
+
+
+ 479
+ short_description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+ 480
+ description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+
+
+ /placeholder
+
+
+ image/svg+xml
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example
new file mode 100644
index 000000000..c6510ea95
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example
@@ -0,0 +1,89 @@
+{
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/5",
+ "VersionInfo": {
+ "id": 581,
+ "versionNo": 5,
+ "status": "ARCHIVED",
+ "modificationDate": "2023-05-24T06:11:50+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2023-05-24T06:09:49+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Features"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/107"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 477,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Features"
+ },
+ {
+ "id": 478,
+ "fieldDefinitionIdentifier": "short_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ },
+ {
+ "id": 479,
+ "fieldDefinitionIdentifier": "short_description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ },
+ {
+ "id": 480,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezrichtext",
+ "fieldValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ }
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/5/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/placeholder",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example
new file mode 100644
index 000000000..9286adb0c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example
@@ -0,0 +1,73 @@
+
+
+
+ 581
+ 5
+ ARCHIVED
+ 2023-05-24T06:11:50+00:00
+
+ 2023-05-24T06:09:49+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Features
+
+
+
+
+
+ 477
+ name
+ eng-GB
+ ezstring
+ Features
+
+
+ 478
+ short_name
+ eng-GB
+ ezstring
+
+
+
+ 479
+ short_description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+ 480
+ description
+ eng-GB
+ ezrichtext
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+
+
+
+
+ /placeholder
+
+
+ image/svg+xml
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/Version.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/Version.xml.example
new file mode 100644
index 000000000..3bb4e3b18
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/Version.xml.example
@@ -0,0 +1,48 @@
+
+
+
+ 45
+ 4
+ DRAFT
+ 2012-02-20T12:00:00
+
+ 22012-02-20T12:00:00
+ ger-DE
+
+ Neuer Titel
+
+
+
+
+
+ 1234
+ title
+ ger-DE
+ Neuer Titel
+
+
+ 1235
+ summary
+ ger-DE
+ Dies ist eine neuse Zusammenfassungy
+
+
+ authors
+ ger-DE
+
+
+
+
+
+
+
+
+
+
+
+ COMMON
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/VersionUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/VersionUpdate.xml.example
new file mode 100644
index 000000000..2fbff5a67
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/VersionUpdate.xml.example
@@ -0,0 +1,21 @@
+
+
+ 2012-02-20T12:00:00
+ ger-DE
+
+
+ 1234
+ title
+ ger-DE
+ Neuer Titel
+
+
+ 1235
+ summary
+ ger-DE
+ Dies ist eine neuse Zusammenfassungy
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.json.example
new file mode 100644
index 000000000..7ccd94776
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.json.example
@@ -0,0 +1,21 @@
+{
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/9/relations",
+ "Relation": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Relation+json",
+ "_href": "/api/ibexa/v2/content/objects/107/versions/9/relations/7",
+ "SourceContent": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/107"
+ },
+ "DestinationContent": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/52"
+ },
+ "RelationType": "LINK"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.xml.example
new file mode 100644
index 000000000..07934ebd3
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.xml.example
@@ -0,0 +1,8 @@
+
+
+
+
+
+ LINK
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.json.example
new file mode 100644
index 000000000..dd5981dc1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.json.example
@@ -0,0 +1,15 @@
+{
+ "Relation": {
+ "_media-type": "application/vnd.ibexa.api.Relation+json",
+ "_href": "/api/ibexa/v2/content/objects/59/versions/2/relations/38",
+ "SourceContent": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/59"
+ },
+ "DestinationContent": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/59"
+ },
+ "RelationType": "COMMON"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.xml.example
new file mode 100644
index 000000000..da36f0d4a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.xml.example
@@ -0,0 +1,6 @@
+
+
+
+
+ COMMON
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.json.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.json.example
new file mode 100644
index 000000000..84e14562a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.json.example
@@ -0,0 +1,7 @@
+{
+ "RelationCreate": {
+ "Destination": {
+ "_href": "/api/ibexa/v2/content/objects/59"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.xml.example
new file mode 100644
index 000000000..0eed6ae84
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/relation_id/GET/Relation.xml.example b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/relation_id/GET/Relation.xml.example
new file mode 100644
index 000000000..4f7e851d1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/relation_id/GET/Relation.xml.example
@@ -0,0 +1,6 @@
+
+
+
+
+ COMMON
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.json.example
new file mode 100644
index 000000000..a180f21cc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.json.example
@@ -0,0 +1,92 @@
+{
+ "ObjectStateGroupList": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroupList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups",
+ "ObjectStateGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2",
+ "id": 2,
+ "identifier": "ez_lock",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Lock"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/3",
+ "id": 3,
+ "identifier": "accessibility",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/3/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Accessibility"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/6",
+ "id": 6,
+ "identifier": "custom-states",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/6/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom Object state"
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.xml.example
new file mode 100644
index 000000000..6d30c9c74
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.xml.example
@@ -0,0 +1,42 @@
+
+
+
+ 2
+ ez_lock
+ eng-GB
+ eng-GB
+
+
+ Lock
+
+
+
+
+
+
+ 3
+ accessibility
+ eng-GB
+ eng-GB
+
+
+ Accessibility
+
+
+
+
+
+
+ 6
+ custom-states
+ eng-GB
+ eng-GB
+
+
+ Custom State
+
+
+ Custom Object state
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.json.example
new file mode 100644
index 000000000..f18e09708
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.json.example
@@ -0,0 +1,30 @@
+{
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7",
+ "id": 7,
+ "identifier": "custom-states",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom Object state"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.xml.example
new file mode 100644
index 000000000..a03639afc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroup.xml.example
@@ -0,0 +1,14 @@
+
+
+ 5
+ custom-states
+ eng-GB
+ eng-GB
+
+
+ Custom State
+
+
+ Custom Object state
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.json.example
new file mode 100644
index 000000000..3e3051b20
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.json.example
@@ -0,0 +1,22 @@
+{
+ "ObjectStateGroupCreate": {
+ "identifier": "custom-states",
+ "defaultLanguageCode": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom Object state"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.xml.example
new file mode 100644
index 000000000..e508acf72
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.xml.example
@@ -0,0 +1,11 @@
+
+
+ custom
+ eng-GB
+
+ Custom State
+
+
+ Custom Object state
+
+
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.json.example
new file mode 100644
index 000000000..f18e09708
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.json.example
@@ -0,0 +1,30 @@
+{
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7",
+ "id": 7,
+ "identifier": "custom-states",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom Object state"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.xml.example
new file mode 100644
index 000000000..c139dad0d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/GET/ObjectStateGroup.xml.example
@@ -0,0 +1,14 @@
+
+
+ 7
+ custom-states
+ eng-GB
+ eng-GB
+
+
+ Custom State
+
+
+ Custom Object state
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example
new file mode 100644
index 000000000..3c57a7018
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example
@@ -0,0 +1,30 @@
+{
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7",
+ "id": 7,
+ "identifier": "custom-states",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7/objectstates"
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Custom State name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Custom Object state"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example
new file mode 100644
index 000000000..9d0860d03
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example
@@ -0,0 +1,14 @@
+
+
+ 7
+ custom-states
+ eng-GB
+ eng-GB
+
+
+ New Custom State name
+
+
+ Custom Object state
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.json.example
new file mode 100644
index 000000000..8510b2684
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.json.example
@@ -0,0 +1,12 @@
+{
+ "ObjectStateGroupUpdate": {
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Custom State name"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.xml.example
new file mode 100644
index 000000000..c0d7b5c7e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.xml.example
@@ -0,0 +1,6 @@
+
+
+
+ New Custom State name
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.json.example
new file mode 100644
index 000000000..f2dc764ec
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.json.example
@@ -0,0 +1,66 @@
+{
+ "ObjectStateList": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateList+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates",
+ "ObjectState": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates/1",
+ "id": 1,
+ "identifier": "not_locked",
+ "priority": 0,
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2"
+ },
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Not locked"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates/2",
+ "id": 2,
+ "identifier": "locked",
+ "priority": 1,
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2"
+ },
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Locked"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.xml.example
new file mode 100644
index 000000000..0f13a16a0
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.xml.example
@@ -0,0 +1,31 @@
+
+
+
+ 1
+ not_locked
+ 0
+
+ eng-GB
+ eng-GB
+
+ Not locked
+
+
+
+
+
+
+ 2
+ locked
+ 1
+
+ eng-GB
+ eng-GB
+
+ Locked
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.json.example
new file mode 100644
index 000000000..723b8c07a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.json.example
@@ -0,0 +1,31 @@
+{
+ "ObjectState": {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7/objectstates/7",
+ "id": 7,
+ "identifier": "new-state",
+ "priority": 0,
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/7"
+ },
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Object State"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.xml.example
new file mode 100644
index 000000000..5fc3fb7de
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectState.xml.example
@@ -0,0 +1,15 @@
+
+
+ 5
+ new-state
+ 0
+
+ eng-GB
+ eng-GB
+
+ New State
+
+
+ New Object State
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.json.example
new file mode 100644
index 000000000..840517259
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.json.example
@@ -0,0 +1,24 @@
+{
+ "ObjectStateCreate": {
+ "identifier": "new-state",
+ "priority": "1",
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New State"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Object State"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.xml.example
new file mode 100644
index 000000000..b021c96d1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.xml.example
@@ -0,0 +1,12 @@
+
+
+ new-state
+ 1
+ eng-GB
+
+ New State
+
+
+ New Object State
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.json.example
new file mode 100644
index 000000000..992d43639
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.json.example
@@ -0,0 +1,31 @@
+{
+ "ObjectState": {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2/objectstates/2",
+ "id": 2,
+ "identifier": "locked",
+ "priority": 1,
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/2"
+ },
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Locked"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.xml.example
new file mode 100644
index 000000000..63924f793
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/GET/ObjectState.xml.example
@@ -0,0 +1,15 @@
+
+
+2
+locked
+1
+
+eng-GB
+eng-GB
+
+ Locked
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example
new file mode 100644
index 000000000..f7e10a139
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example
@@ -0,0 +1,31 @@
+{
+ "ObjectState": {
+ "_media-type": "application/vnd.ibexa.api.ObjectState+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/6/objectstates/9",
+ "id": 9,
+ "identifier": "closed",
+ "priority": 1,
+ "ObjectStateGroup": {
+ "_media-type": "application/vnd.ibexa.api.ObjectStateGroup+json",
+ "_href": "/api/ibexa/v2/content/objectstategroups/6"
+ },
+ "defaultLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Object State name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example
new file mode 100644
index 000000000..20f9c542e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example
@@ -0,0 +1,15 @@
+
+
+ 2
+ locked
+ 1
+
+ eng-GB
+ eng-GB
+
+ New Object State name
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.json.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.json.example
new file mode 100644
index 000000000..519d608f2
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.json.example
@@ -0,0 +1,12 @@
+{
+ "ObjectStateUpdate": {
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New Object State name"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.xml.example
new file mode 100644
index 000000000..8b7271316
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.xml.example
@@ -0,0 +1,8 @@
+
+
+ 3
+ eng-GB
+
+ New Object State name
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.json.example b/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.json.example
new file mode 100644
index 000000000..4747a2a9c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.json.example
@@ -0,0 +1,50 @@
+{
+ "SectionList": {
+ "_media-type": "application/vnd.ibexa.api.SectionList+json",
+ "_href": "/api/ibexa/v2/content/sections",
+ "Section": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1",
+ "sectionId": 1,
+ "identifier": "standard",
+ "name": "Standard"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2",
+ "sectionId": 2,
+ "identifier": "users",
+ "name": "Users"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/3",
+ "sectionId": 3,
+ "identifier": "media",
+ "name": "Media"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/6",
+ "sectionId": 6,
+ "identifier": "form",
+ "name": "Form"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/7",
+ "sectionId": 7,
+ "identifier": "template",
+ "name": "Template"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/8",
+ "sectionId": 8,
+ "identifier": "restricted",
+ "name": "Restricted"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.xml.example
new file mode 100644
index 000000000..13de53b1d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/GET/SectionList.xml.example
@@ -0,0 +1,33 @@
+
+
+
+ 1
+ standard
+ Standard
+
+
+
+
+
+ 7
+ template
+ Template
+
+
+ 8
+ restricted
+ Restricted
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.json.example b/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.json.example
new file mode 100644
index 000000000..46ac7c049
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.json.example
@@ -0,0 +1,9 @@
+{
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/13",
+ "sectionId": 13,
+ "identifier": "restricted",
+ "name": "Restricted"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.xml.example
new file mode 100644
index 000000000..5dd9f2635
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/POST/Section.xml.example
@@ -0,0 +1,6 @@
+
+
+ 7
+ restricted
+ Restricted
+
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.json.example b/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.json.example
new file mode 100644
index 000000000..f4b5bcfa1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.json.example
@@ -0,0 +1,6 @@
+{
+ "SectionInput": {
+ "identifier": "restricted",
+ "name": "Restricted"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.xml.example
new file mode 100644
index 000000000..d09d79015
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/POST/SectionInput.xml.example
@@ -0,0 +1,5 @@
+
+
+ restricted
+ Restricted
+
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.json.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.json.example
new file mode 100644
index 000000000..4a14d9f7c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.json.example
@@ -0,0 +1,9 @@
+{
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/10",
+ "sectionId": 10,
+ "identifier": "design",
+ "name": "Design"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.xml.example
new file mode 100644
index 000000000..2f7d484de
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/GET/Section.xml.example
@@ -0,0 +1,6 @@
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example
new file mode 100644
index 000000000..84a448514
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example
@@ -0,0 +1,9 @@
+{
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/7",
+ "sectionId": 7,
+ "identifier": "template",
+ "name": "Template"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example
new file mode 100644
index 000000000..89ba20fd7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example
@@ -0,0 +1,6 @@
+
+
+ 7
+ template
+ Template
+
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.json.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.json.example
new file mode 100644
index 000000000..6e93f4201
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.json.example
@@ -0,0 +1,6 @@
+{
+ "SectionInput": {
+ "identifier": "template",
+ "name": "Template"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.xml.example b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.xml.example
new file mode 100644
index 000000000..1160bc416
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/sections/section_id/PATCH/SectionInput.xml.example
@@ -0,0 +1,5 @@
+
+
+ template
+ Template
+
diff --git a/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.json.example b/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.json.example
new file mode 100644
index 000000000..5dd83e3ce
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.json.example
@@ -0,0 +1,146 @@
+{
+ "Trash": {
+ "_media-type": "application/vnd.ibexa.api.Trash+json",
+ "_href": "/api/ibexa/v2/content/trash",
+ "TrashItem": [
+ {
+ "_media-type": "application/vnd.ibexa.api.TrashItem+json",
+ "_href": "/api/ibexa/v2/content/trash/87",
+ "id": 87,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57"
+ },
+ "pathString": "/1/2/57/87/",
+ "depth": 3,
+ "childCount": 0,
+ "remoteId": "7cc6565354858f39a794bf64aa2c2761",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/91"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/91",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/91",
+ "_remoteId": "de906bef76f08700662bfaf1579871f0",
+ "_id": 91,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "Name": "test_article",
+ "TranslatedName": "test_article",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/91/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/91/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/91/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/11"
+ },
+ "lastModificationDate": "2021-07-19T08:31:01+00:00",
+ "publishedDate": "2021-07-19T08:31:01+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": false,
+ "isHidden": false,
+ "status": "TRASHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/91/objectstates"
+ }
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.TrashItem+json",
+ "_href": "/api/ibexa/v2/content/trash/89",
+ "id": 89,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2"
+ },
+ "pathString": "/1/2/89/",
+ "depth": 2,
+ "childCount": 0,
+ "remoteId": "256c2e7d71e927bab32a901878827312",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/96"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/96",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/96",
+ "_remoteId": "d5bad9eb55cfe8572adf04452a2b206e",
+ "_id": 96,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1"
+ },
+ "Name": "All Articles test",
+ "TranslatedName": "All Articles test",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/96/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/96/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/96/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "lastModificationDate": "2021-07-19T12:43:02+00:00",
+ "publishedDate": "2021-07-19T12:42:47+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 2,
+ "alwaysAvailable": true,
+ "isHidden": false,
+ "status": "TRASHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/96/objectstates"
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.xml.example b/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.xml.example
new file mode 100644
index 000000000..feab5489e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/trash/GET/Trash.xml.example
@@ -0,0 +1,34 @@
+
+
+
+ 58
+ 0
+ false
+ false
+
+ /1/2/56/58/
+ 3
+ 0
+ 59800915ad2eb8514de0bebe84f6ccba
+
+ PATH
+ ASC
+
+
+
+ Folder 1
+
+
+
+
+
+ 2019-02-06T09:03:09+01:00
+ 2019-02-06T09:03:09+01:00
+ eng-GB
+ 1
+ true
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.json.example b/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.json.example
new file mode 100644
index 000000000..86fd0f2eb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.json.example
@@ -0,0 +1,71 @@
+{
+ "TrashItem": {
+ "_media-type": "application/vnd.ibexa.api.TrashItem+json",
+ "_href": "/api/ibexa/v2/content/trash/87",
+ "id": 87,
+ "priority": 0,
+ "hidden": false,
+ "invisible": false,
+ "ParentLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/2/57"
+ },
+ "pathString": "/1/2/57/87/",
+ "depth": 3,
+ "childCount": 0,
+ "remoteId": "7cc6565354858f39a794bf64aa2c2761",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.Content+json",
+ "_href": "/api/ibexa/v2/content/objects/91"
+ },
+ "sortField": "PATH",
+ "sortOrder": "ASC",
+ "ContentInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/91",
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/91",
+ "_remoteId": "de906bef76f08700662bfaf1579871f0",
+ "_id": 91,
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2"
+ },
+ "Name": "test_article",
+ "TranslatedName": "test_article",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/91/versions"
+ },
+ "CurrentVersion": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/91/currentversion"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/1"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/91/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/11"
+ },
+ "lastModificationDate": "2021-07-19T08:31:01+00:00",
+ "publishedDate": "2021-07-19T08:31:01+00:00",
+ "mainLanguageCode": "eng-GB",
+ "currentVersionNo": 1,
+ "alwaysAvailable": false,
+ "isHidden": false,
+ "status": "TRASHED",
+ "ObjectStates": {
+ "_media-type": "application/vnd.ibexa.api.ContentObjectStates+json",
+ "_href": "/api/ibexa/v2/content/objects/91/objectstates"
+ }
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.xml.example b/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.xml.example
new file mode 100644
index 000000000..1c886e140
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.xml.example
@@ -0,0 +1,33 @@
+
+
+ 81
+ 0
+ false
+ false
+
+ /1/2/42/81/
+ 3
+ 0
+ 135e8a84b61848a67be36e9552d2724d
+
+ PATH
+ ASC
+
+
+
+ Folder 1
+
+
+
+
+
+ 2019-04-25T12:45:58+02:00
+ 2019-04-25T12:45:58+02:00
+ eng-GB
+ 1
+ true
+ TRASHED
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.json.example
new file mode 100644
index 000000000..45838cbc7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.json.example
@@ -0,0 +1,68 @@
+{
+ "ContentTypeGroupList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupList+json",
+ "_href": "/api/ibexa/v2/content/typegroups",
+ "ContentTypeGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1",
+ "id": 1,
+ "identifier": "Content",
+ "created": "2002-09-05T09:08:48+00:00",
+ "modified": "2002-10-06T16:35:06+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "ContentTypes": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfoList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1/types"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/2",
+ "id": 2,
+ "identifier": "Users",
+ "created": "2002-09-05T09:09:01+00:00",
+ "modified": "2002-10-06T16:35:13+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "ContentTypes": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfoList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/2/types"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/3",
+ "id": 3,
+ "identifier": "Media",
+ "created": "2002-09-14T13:22:23+00:00",
+ "modified": "2002-10-06T16:35:20+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "ContentTypes": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfoList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/3/types"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.xml.example
new file mode 100644
index 000000000..7794b023a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.xml.example
@@ -0,0 +1,30 @@
+
+
+
+ 1
+ Content
+ 2002-09-05T11:08:48+02:00
+ 2002-10-06T18:35:06+02:00
+
+
+
+
+
+ 2
+ Users
+ 2002-09-05T11:09:01+02:00
+ 2002-10-06T18:35:13+02:00
+
+
+
+
+
+ 3
+ Media
+ 2002-09-14T15:22:23+02:00
+ 2002-10-06T18:35:20+02:00
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.json.example
new file mode 100644
index 000000000..5cd4cdbcc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.json.example
@@ -0,0 +1,22 @@
+{
+ "ContentTypeGroup": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/6",
+ "id": 6,
+ "identifier": "newContentTypeGroup",
+ "created": "2021-08-11T09:44:18+00:00",
+ "modified": "2021-08-11T09:44:18+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "ContentTypes": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfoList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/6/types"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.xml.example
new file mode 100644
index 000000000..8c63d3a72
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.xml.example
@@ -0,0 +1,10 @@
+
+
+ 7
+ newContentTypeGroup
+ 2012-02-31T12:45:00
+ 2012-02-31T12:45:00
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.json.example
new file mode 100644
index 000000000..164105095
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.json.example
@@ -0,0 +1,5 @@
+{
+ "ContentTypeGroupInput": {
+ "identifier": "newContentTypeGroup"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.xml.example
new file mode 100644
index 000000000..f88b35a97
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.xml.example
@@ -0,0 +1,4 @@
+
+
+ newContentTypeGroup
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.json.example
new file mode 100644
index 000000000..cfcff3bb4
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.json.example
@@ -0,0 +1,1595 @@
+{
+ "ContentTypeList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1/types",
+ "ContentType": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2",
+ "id": 2,
+ "status": "DEFINED",
+ "identifier": "article",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2021-06-28T11:31:22+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/2/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft"
+ },
+ "remoteId": "c15b600eb9198b1924063b5a68758232",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/1",
+ "id": 1,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/152",
+ "id": 152,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/153",
+ "id": 153,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/120",
+ "id": 120,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/121",
+ "id": 121,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/123",
+ "id": 123,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/195",
+ "id": 195,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/50",
+ "id": 50,
+ "status": "DEFINED",
+ "identifier": "copy_of_article_50",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-07-14T10:30:00+00:00",
+ "modificationDate": "2021-07-14T10:30:00+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/50/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/50/draft"
+ },
+ "remoteId": "fc9434492469d136ffe13377bfdcbb28",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/197",
+ "id": 197,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/198",
+ "id": 198,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/199",
+ "id": 199,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/200",
+ "id": 200,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/201",
+ "id": 201,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/202",
+ "id": 202,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/203",
+ "id": 203,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/44",
+ "id": 44,
+ "status": "DEFINED",
+ "identifier": "dog_breed",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Dog Breed"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-06-28T11:28:00+00:00",
+ "modificationDate": "2021-06-28T11:29:02+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/44/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/44/draft"
+ },
+ "remoteId": "b348c95f7c573d4d502d6b59f80e618a",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/190",
+ "id": 190,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/191",
+ "id": 191,
+ "identifier": "photo",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Photo"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/192",
+ "id": 192,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "content",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Full Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1",
+ "id": 1,
+ "status": "DEFINED",
+ "identifier": "folder",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Folder"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2015-11-29T21:14:32+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/1/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1/draft"
+ },
+ "remoteId": "a3d405b81be900468eb153d774f4f0d2",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/4",
+ "id": 4,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "Folder",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/155",
+ "id": 155,
+ "identifier": "short_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 100,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/119",
+ "id": 119,
+ "identifier": "short_description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/156",
+ "id": 156,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/55",
+ "id": 55,
+ "status": "DEFINED",
+ "identifier": "folder_55",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Folder"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-07-28T07:57:22+00:00",
+ "modificationDate": "2021-07-28T07:57:34+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/55/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/55/draft"
+ },
+ "remoteId": "4eb7bc76f6d0bd1d5ded2d8936cc6afb",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/55/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/55/fieldDefinitions/210",
+ "id": 210,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "Folder",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/55/fieldDefinitions/211",
+ "id": 211,
+ "identifier": "short_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 100,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/55/fieldDefinitions/212",
+ "id": 212,
+ "identifier": "short_description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/55/fieldDefinitions/213",
+ "id": 213,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43",
+ "id": 43,
+ "status": "DEFINED",
+ "identifier": "form",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2018-09-17T06:46:13+00:00",
+ "modificationDate": "2018-09-17T06:47:14+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/43/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43/draft"
+ },
+ "remoteId": "6f7f21df775a33c1e4bbc76b48c38476",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/188",
+ "id": 188,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/189",
+ "id": 189,
+ "identifier": "form",
+ "fieldType": "ezform",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "fields": [],
+ "content_id": null,
+ "content_field_id": null,
+ "language_code": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/45",
+ "id": 45,
+ "status": "DEFINED",
+ "identifier": "tip",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Tip"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-06-28T11:29:19+00:00",
+ "modificationDate": "2021-07-26T09:33:06+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/45/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/45/draft"
+ },
+ "remoteId": "e6490e8a785edacd48629f2022be3125",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/193",
+ "id": 193,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/194",
+ "id": 194,
+ "identifier": "body",
+ "fieldType": "eztext",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "textRows": 10
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/204",
+ "id": 204,
+ "identifier": "richtext",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "content",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "richtext"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42",
+ "id": 42,
+ "status": "DEFINED",
+ "identifier": "landing_page",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ },
+ "creationDate": "2015-07-03T12:00:26+00:00",
+ "modificationDate": "2015-07-03T12:00:26+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/42/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42/draft"
+ },
+ "remoteId": "60c03e9758465eb69d56b3afb6adf18e",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/185",
+ "id": 185,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 10,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/186",
+ "id": 186,
+ "identifier": "description",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 20,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page description"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/187",
+ "id": 187,
+ "identifier": "page",
+ "fieldType": "ezlandingpage",
+ "fieldGroup": "content",
+ "position": 30,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "layout": "default",
+ "zones": [
+ {
+ "id": "default_id",
+ "name": "default",
+ "blocks": []
+ }
+ ]
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "fieldSettings": {
+ "availableBlocks": null,
+ "availableLayouts": null,
+ "editorMode": "page_view_mode"
+ },
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.xml.example
new file mode 100644
index 000000000..e8def2575
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/GET/ContentTypeGroup.xml.example
@@ -0,0 +1,1034 @@
+
+
+
+ 2
+ DEFINED
+ article
+
+ Article
+
+
+
+
+ 2002-06-18T09:21:38+00:00
+ 2021-06-28T11:31:22+00:00
+
+
+
+
+ c15b600eb9198b1924063b5a68758232
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 1
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+
+
+ 255
+
+
+
+
+
+ 152
+ short_title
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short title
+
+
+
+
+
+
+
+ 255
+
+
+
+
+
+ 153
+ author
+ ezauthor
+
+ 3
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+
+
+ 1
+
+
+
+
+ 120
+ intro
+ ezrichtext
+
+ 4
+ true
+ true
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Intro
+
+
+
+
+
+
+
+
+ 121
+ body
+ ezrichtext
+
+ 5
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Body
+
+
+
+
+
+
+
+
+ 123
+ enable_comments
+ ezboolean
+
+ 6
+ false
+ false
+ false
+ false
+ false
+
+ Enable comments
+
+
+
+
+
+
+
+
+ 195
+ image
+ ezimageasset
+ content
+ 7
+ false
+ false
+ false
+
+
+
+
+
+ false
+
+ Image
+
+
+
+
+
+
+
+
+
+
+ 50
+ DEFINED
+ copy_of_article_50
+
+ Article
+
+
+
+
+ 2021-07-14T10:30:00+00:00
+ 2021-07-14T10:30:00+00:00
+
+
+
+
+ fc9434492469d136ffe13377bfdcbb28
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 197
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+
+
+ 255
+
+
+
+
+
+ 198
+ short_title
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short title
+
+
+
+
+
+
+
+ 255
+
+
+
+
+
+ 199
+ author
+ ezauthor
+
+ 3
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+
+
+ 1
+
+
+
+
+ 200
+ intro
+ ezrichtext
+
+ 4
+ true
+ true
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Intro
+
+
+
+
+
+
+
+
+ 201
+ body
+ ezrichtext
+
+ 5
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Body
+
+
+
+
+
+
+
+
+ 202
+ enable_comments
+ ezboolean
+
+ 6
+ false
+ false
+ false
+ false
+ false
+
+ Enable comments
+
+
+
+
+
+
+
+
+ 203
+ image
+ ezimageasset
+ content
+ 7
+ false
+ false
+ false
+
+
+
+
+
+ false
+
+ Image
+
+
+
+
+
+
+
+
+
+
+ 44
+ DEFINED
+ dog_breed
+
+ Dog Breed
+
+
+
+
+ 2021-06-28T11:28:00+00:00
+ 2021-06-28T11:29:02+00:00
+
+
+
+
+ b348c95f7c573d4d502d6b59f80e618a
+
+ <name>
+ false
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 190
+ name
+ ezstring
+ content
+ 1
+ true
+ false
+ false
+
+ true
+
+ Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 191
+ photo
+ ezimageasset
+ content
+ 2
+ true
+ false
+ false
+
+
+
+
+
+ true
+
+ Photo
+
+
+
+
+
+
+
+
+ 192
+ description
+ ezrichtext
+ content
+ 3
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Full Description
+
+
+
+
+
+
+
+
+
+
+ 1
+ DEFINED
+ folder
+
+ Folder
+
+
+ 2002-06-18T09:21:38+00:00
+ 2015-11-29T21:14:32+00:00
+
+
+
+
+ a3d405b81be900468eb153d774f4f0d2
+
+ <short_name|name>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
+
+ 4
+ name
+ ezstring
+
+ 1
+ true
+ true
+ false
+ Folder
+ true
+
+ Name
+
+
+
+
+
+ 255
+
+
+
+
+
+ 155
+ short_name
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short name
+
+
+
+
+
+ 100
+
+
+
+
+
+ 119
+ short_description
+ ezrichtext
+
+ 3
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Short description
+
+
+
+
+
+
+ 156
+ description
+ ezrichtext
+
+ 4
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Description
+
+
+
+
+
+
+
+
+ 55
+ DEFINED
+ folder_55
+
+ Folder
+
+
+
+
+ 2021-07-28T07:57:22+00:00
+ 2021-07-28T07:57:34+00:00
+
+
+
+
+ 4eb7bc76f6d0bd1d5ded2d8936cc6afb
+
+ <short_name|name>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
+
+ 210
+ name
+ ezstring
+
+ 1
+ true
+ true
+ false
+ Folder
+ true
+
+ Name
+
+
+
+
+
+
+
+ 255
+
+
+
+
+
+ 211
+ short_name
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short name
+
+
+
+
+
+
+
+ 100
+
+
+
+
+
+ 212
+ short_description
+ ezrichtext
+
+ 3
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Short description
+
+
+
+
+
+
+
+
+ 213
+ description
+ ezrichtext
+
+ 4
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Description
+
+
+
+
+
+
+
+
+
+
+ 43
+ DEFINED
+ form
+
+ Form
+
+
+ 2018-09-17T06:46:13+00:00
+ 2018-09-17T06:47:14+00:00
+
+
+
+
+ 6f7f21df775a33c1e4bbc76b48c38476
+
+ <title>
+ false
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 188
+ title
+ ezstring
+ content
+ 1
+ true
+ true
+ false
+
+ true
+
+ Title
+
+
+
+
+
+
+
+
+
+
+
+ 189
+ form
+ ezform
+ content
+ 2
+ true
+ false
+ false
+
+
+
+
+
+
+ false
+
+ Form
+
+
+
+
+
+
+
+
+ 45
+ DEFINED
+ tip
+
+ Tip
+
+
+
+
+ 2021-06-28T11:29:19+00:00
+ 2021-07-26T09:33:06+00:00
+
+
+
+
+ e6490e8a785edacd48629f2022be3125
+
+ <title>
+ false
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 193
+ title
+ ezstring
+ content
+ 1
+ true
+ false
+ false
+
+ true
+
+ Title
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 194
+ body
+ eztext
+ content
+ 2
+ true
+ false
+ false
+
+ true
+
+ Body
+
+
+
+
+
+ 10
+
+
+
+
+ 204
+ richtext
+ ezrichtext
+ content
+ 3
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ richtext
+
+
+
+
+
+
+
+
+
+
+ 42
+ DEFINED
+ landing_page
+
+ Landing page
+
+
+
+
+ 2015-07-03T12:00:26+00:00
+ 2015-07-03T12:00:26+00:00
+
+
+
+
+ 60c03e9758465eb69d56b3afb6adf18e
+
+ <name>
+ true
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 185
+ name
+ ezstring
+ content
+ 10
+ true
+ true
+ false
+
+ true
+
+ Title
+
+
+ Title
+
+
+
+
+
+
+
+
+
+
+ 186
+ description
+ ezstring
+ content
+ 20
+ true
+ true
+ false
+
+ true
+
+ Description
+
+
+ Landing page description
+
+
+
+
+
+
+
+
+
+
+ 187
+ page
+ ezlandingpage
+ content
+ 30
+ true
+ false
+ false
+
+ default
+
+
+ default_id
+ default
+
+
+
+
+ false
+
+ Landing page
+
+
+ Landing page
+
+
+
+
+ page_view_mode
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.json.example
new file mode 100644
index 000000000..5235bc58c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.json.example
@@ -0,0 +1,22 @@
+{
+ "ContentTypeGroup": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/4",
+ "id": 4,
+ "identifier": "updatedIdentifer",
+ "created": "2021-08-11T09:44:18+00:00",
+ "modified": "2021-08-11T10:10:04+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "ContentTypes": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfoList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/6/types"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.xml.example
new file mode 100644
index 000000000..2357f9257
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.xml.example
@@ -0,0 +1,10 @@
+
+
+ 4
+ updatedIdentifer
+ 2002-09-05T11:08:48+02:00
+ 2019-02-22T14:42:55+01:00
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.json.example
new file mode 100644
index 000000000..bf3fa9ebc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.json.example
@@ -0,0 +1,5 @@
+{
+ "ContentTypeGroupInput": {
+ "identifier": "updatedIdentifer"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.xml.example
new file mode 100644
index 000000000..2a79ff0f6
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroupInput.xml.example
@@ -0,0 +1,4 @@
+
+
+ updatedIdentifer
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.json.example
new file mode 100644
index 000000000..c7c2076fb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.json.example
@@ -0,0 +1,2011 @@
+{
+ "ContentTypeList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeList+json",
+ "_href": "/api/ibexa/v2/content/types",
+ "ContentType": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2",
+ "id": 2,
+ "status": "DEFINED",
+ "identifier": "article",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2021-06-28T11:31:22+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/2/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft"
+ },
+ "remoteId": "c15b600eb9198b1924063b5a68758232",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/1",
+ "id": 1,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/152",
+ "id": 152,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/153",
+ "id": 153,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/120",
+ "id": 120,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/121",
+ "id": 121,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/123",
+ "id": 123,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/195",
+ "id": 195,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/50",
+ "id": 50,
+ "status": "DEFINED",
+ "identifier": "copy_of_article_50",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-07-14T10:30:00+00:00",
+ "modificationDate": "2021-07-14T10:30:00+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/50/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/50/draft"
+ },
+ "remoteId": "fc9434492469d136ffe13377bfdcbb28",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/197",
+ "id": 197,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/198",
+ "id": 198,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/199",
+ "id": 199,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/200",
+ "id": 200,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/201",
+ "id": 201,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/202",
+ "id": 202,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/50/fieldDefinitions/203",
+ "id": 203,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/44",
+ "id": 44,
+ "status": "DEFINED",
+ "identifier": "dog_breed",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Dog Breed"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-06-28T11:28:00+00:00",
+ "modificationDate": "2021-06-28T11:29:02+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/44/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/44/draft"
+ },
+ "remoteId": "b348c95f7c573d4d502d6b59f80e618a",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/190",
+ "id": 190,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/191",
+ "id": 191,
+ "identifier": "photo",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Photo"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/44/fieldDefinitions/192",
+ "id": 192,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "content",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Full Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1",
+ "id": 1,
+ "status": "DEFINED",
+ "identifier": "folder",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Folder"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2015-11-29T21:14:32+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/1/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1/draft"
+ },
+ "remoteId": "a3d405b81be900468eb153d774f4f0d2",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/4",
+ "id": 4,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "Folder",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/155",
+ "id": 155,
+ "identifier": "short_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 100,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/119",
+ "id": 119,
+ "identifier": "short_description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/156",
+ "id": 156,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43",
+ "id": 43,
+ "status": "DEFINED",
+ "identifier": "form",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2018-09-17T06:46:13+00:00",
+ "modificationDate": "2018-09-17T06:47:14+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/43/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43/draft"
+ },
+ "remoteId": "6f7f21df775a33c1e4bbc76b48c38476",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/188",
+ "id": 188,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/189",
+ "id": 189,
+ "identifier": "form",
+ "fieldType": "ezform",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "fields": [],
+ "content_id": null,
+ "content_field_id": null,
+ "language_code": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/45",
+ "id": 45,
+ "status": "DEFINED",
+ "identifier": "tip",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Tip"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2021-06-28T11:29:19+00:00",
+ "modificationDate": "2021-07-26T09:33:06+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/45/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/45/draft"
+ },
+ "remoteId": "e6490e8a785edacd48629f2022be3125",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/193",
+ "id": 193,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/194",
+ "id": 194,
+ "identifier": "body",
+ "fieldType": "eztext",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "textRows": 10
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/45/fieldDefinitions/204",
+ "id": 204,
+ "identifier": "richtext",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "content",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "richtext"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42",
+ "id": 42,
+ "status": "DEFINED",
+ "identifier": "landing_page",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ },
+ "creationDate": "2015-07-03T12:00:26+00:00",
+ "modificationDate": "2015-07-03T12:00:26+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/42/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42/draft"
+ },
+ "remoteId": "60c03e9758465eb69d56b3afb6adf18e",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/185",
+ "id": 185,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 10,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/186",
+ "id": 186,
+ "identifier": "description",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 20,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page description"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/187",
+ "id": 187,
+ "identifier": "page",
+ "fieldType": "ezlandingpage",
+ "fieldGroup": "content",
+ "position": 30,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "layout": "default",
+ "zones": [
+ {
+ "id": "default_id",
+ "name": "default",
+ "blocks": []
+ }
+ ]
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "fieldSettings": {
+ "availableBlocks": null,
+ "availableLayouts": null,
+ "editorMode": "page_view_mode"
+ },
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4",
+ "id": 4,
+ "status": "DEFINED",
+ "identifier": "user",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "User"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2004-04-15T08:39:24+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/4/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4/draft"
+ },
+ "remoteId": "40faa822edc579b02c25f6bb7beec3ad",
+ "urlAliasSchema": null,
+ "nameSchema": " ",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions/8",
+ "id": 8,
+ "identifier": "first_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "First name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions/9",
+ "id": 9,
+ "identifier": "last_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Last name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions/12",
+ "id": 12,
+ "identifier": "user_account",
+ "fieldType": "ezuser",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": false,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "User account"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": {
+ "PasswordTTL": 0,
+ "PasswordTTLWarning": 0,
+ "RequireUniqueEmail": false,
+ "UsernamePattern": "^[^@]+$"
+ },
+ "validatorConfiguration": {
+ "PasswordValueValidator": {
+ "requireAtLeastOneUpperCaseCharacter": true,
+ "requireAtLeastOneLowerCaseCharacter": true,
+ "requireAtLeastOneNumericCharacter": true,
+ "requireAtLeastOneNonAlphanumericCharacter": false,
+ "requireNewPassword": false,
+ "minLength": 10
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions/179",
+ "id": 179,
+ "identifier": "signature",
+ "fieldType": "eztext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Signature"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": {
+ "textRows": 10
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/4/fieldDefinitions/180",
+ "id": 180,
+ "identifier": "image",
+ "fieldType": "ezimage",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "FileSizeValidator": {
+ "maxFileSize": 10
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/3",
+ "id": 3,
+ "status": "DEFINED",
+ "identifier": "user_group",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "User group"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2003-03-24T08:32:23+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/3/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/3/draft"
+ },
+ "remoteId": "25b4268cdcd01921b808a0d854b877ef",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/3/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/3/fieldDefinitions/6",
+ "id": 6,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/3/fieldDefinitions/7",
+ "id": 7,
+ "identifier": "description",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/12",
+ "id": 12,
+ "status": "DEFINED",
+ "identifier": "file",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "File"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2003-05-08T09:17:52+00:00",
+ "modificationDate": "2003-05-08T09:21:09+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/12/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/12/draft"
+ },
+ "remoteId": "637d58bfddf164627bdfd265733280a0",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/12/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/12/fieldDefinitions/146",
+ "id": 146,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New file",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/12/fieldDefinitions/147",
+ "id": 147,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/12/fieldDefinitions/148",
+ "id": 148,
+ "identifier": "file",
+ "fieldType": "ezbinaryfile",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "File"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "FileSizeValidator": {
+ "maxFileSize": null
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/5",
+ "id": 5,
+ "status": "DEFINED",
+ "identifier": "image",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-09-08T11:36:32+00:00",
+ "modificationDate": "2003-03-24T08:33:04+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/5/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/5/draft"
+ },
+ "remoteId": "f6df12aa74e36230eb675f364fccd25a",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/5/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/5/fieldDefinitions/116",
+ "id": 116,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 150,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/5/fieldDefinitions/117",
+ "id": 117,
+ "identifier": "caption",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Caption"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/5/fieldDefinitions/118",
+ "id": 118,
+ "identifier": "image",
+ "fieldType": "ezimage",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "FileSizeValidator": {
+ "maxFileSize": 10
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.xml.example
new file mode 100644
index 000000000..097f475b1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.xml.example
@@ -0,0 +1,49 @@
+
+
+
+ 2
+ DEFINED
+ article
+
+ Article
+
+
+ 2002-06-18T11:21:38+02:00
+ 2004-04-20T11:56:29+02:00
+
+
+
+
+ c15b600eb9198b1924063b5a68758232
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 1
+ DEFINED
+ folder
+
+ Folder
+
+
+ 2002-06-18T11:21:38+02:00
+ 2015-11-29T22:14:32+01:00
+
+
+
+
+ a3d405b81be900468eb153d774f4f0d2
+
+ <short_name|name>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeList.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeList.xml.example
new file mode 100644
index 000000000..b33671c66
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeList.xml.example
@@ -0,0 +1,184 @@
+
+
+
+ 2
+ DEFINED
+ article
+
+ Article
+
+
+ 2002-06-18T11:21:38+02:00
+ 2004-04-20T11:56:29+02:00
+
+
+
+
+ c15b600eb9198b1924063b5a68758232
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 1
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+ 255
+
+
+
+
+ 152
+ short_title
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short title
+
+
+
+
+
+ 255
+
+
+
+
+ 153
+ author
+ ezauthor
+
+ 3
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+ 1
+
+
+
+
+ 120
+ intro
+ ezrichtext
+
+ 4
+ true
+ true
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Intro
+
+
+
+
+
+
+ 121
+ body
+ ezrichtext
+
+ 5
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Body
+
+
+
+
+
+
+ 123
+ enable_comments
+ ezboolean
+
+ 6
+ false
+ false
+ false
+ false
+ false
+
+ Enable comments
+
+
+
+
+
+
+ 154
+ image
+ ezobjectrelation
+
+ 7
+ true
+ false
+ false
+
+
+
+ true
+
+ Image
+
+
+
+ SELECTION_BROWSE
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentType.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentType.xml.example
new file mode 100644
index 000000000..beac49c71
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentType.xml.example
@@ -0,0 +1,52 @@
+
+
+ 20
+ DRAFT
+ newContentType
+
+ New content type
+
+
+ This is a description
+
+ 2019-02-26T09:39:58+01:00
+ 2019-02-26T09:39:58+01:00
+
+
+
+
+ remoteId-qwert548
+ <title>
+ <title>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
+
+ 223
+ title
+ ezstring
+ content
+ 1
+ true
+ true
+ false
+ New Title
+ true
+
+ Title
+
+
+ This is the title
+
+
+
+
+ 0
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.json.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.json.example
new file mode 100644
index 000000000..175bf7100
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.json.example
@@ -0,0 +1,86 @@
+{
+ "ContentTypeCreate": {
+ "identifier": "new_content_type",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "New content type"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "This is a description"
+ }
+ ]
+ },
+ "remoteId": "remoteId-qwerty548",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "FieldDefinition": [
+ {
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New Title",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "This is the title"
+ }
+ ]
+ }
+ },
+ {
+ "identifier": "summary",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Summary"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "This is the summary"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.xml.example
new file mode 100644
index 000000000..261e7a475
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.xml.example
@@ -0,0 +1,56 @@
+
+
+ newContentType
+
+ New content type
+
+
+ This is a description
+
+ remoteId-qwert548
+ <title>
+ <title>
+ true
+ eng-US
+ true
+ PATH
+ ASC
+
+
+ title
+ ezstring
+ content
+ 1
+ true
+ true
+ false
+ New Title
+ true
+
+ Title
+
+
+ This is the title
+
+
+
+ summary
+ ezxmltext
+ content
+ 2
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="utf-8"?><section/>
+
+ true
+
+ Summary
+
+
+ This is the summary
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example b/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example
new file mode 100644
index 000000000..31c1f62d1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example
@@ -0,0 +1,733 @@
+{
+ "ContentTypeList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1/types",
+ "ContentType": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2",
+ "id": 2,
+ "status": "DEFINED",
+ "identifier": "article",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2004-04-20T09:56:29+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/2/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft"
+ },
+ "remoteId": "c15b600eb9198b1924063b5a68758232",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/1",
+ "id": 1,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/152",
+ "id": 152,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/153",
+ "id": 153,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/120",
+ "id": 120,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/121",
+ "id": 121,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/123",
+ "id": 123,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/154",
+ "id": 154,
+ "identifier": "image",
+ "fieldType": "ezobjectrelation",
+ "fieldGroup": "",
+ "position": 7,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": {
+ "selectionMethod": "SELECTION_BROWSE",
+ "selectionRoot": "",
+ "selectionContentTypes": []
+ },
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1",
+ "id": 1,
+ "status": "DEFINED",
+ "identifier": "folder",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Folder"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2015-11-29T21:14:32+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/1/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1/draft"
+ },
+ "remoteId": "a3d405b81be900468eb153d774f4f0d2",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/4",
+ "id": 4,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "Folder",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/155",
+ "id": 155,
+ "identifier": "short_name",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 100,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/119",
+ "id": 119,
+ "identifier": "short_description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/1/fieldDefinitions/156",
+ "id": 156,
+ "identifier": "description",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43",
+ "id": 43,
+ "status": "DEFINED",
+ "identifier": "form",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2018-09-17T06:46:13+00:00",
+ "modificationDate": "2018-09-17T06:47:14+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/43/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/43/draft"
+ },
+ "remoteId": "6f7f21df775a33c1e4bbc76b48c38476",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": false,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/188",
+ "id": 188,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/43/fieldDefinitions/189",
+ "id": 189,
+ "identifier": "form",
+ "fieldType": "ezform",
+ "fieldGroup": "content",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "fields": [],
+ "content_id": null,
+ "content_field_id": null,
+ "language_code": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Form"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42",
+ "id": 42,
+ "status": "DEFINED",
+ "identifier": "landing_page",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": ""
+ }
+ ]
+ },
+ "creationDate": "2015-07-03T12:00:26+00:00",
+ "modificationDate": "2015-07-03T12:00:26+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/42/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/42/draft"
+ },
+ "remoteId": "60c03e9758465eb69d56b3afb6adf18e",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PUBLISHED",
+ "defaultSortOrder": "DESC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/185",
+ "id": 185,
+ "identifier": "name",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 10,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/186",
+ "id": 186,
+ "identifier": "description",
+ "fieldType": "ezstring",
+ "fieldGroup": "content",
+ "position": 20,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Description"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page description"
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": null,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/42/fieldDefinitions/187",
+ "id": 187,
+ "identifier": "page",
+ "fieldType": "ezlandingpage",
+ "fieldGroup": "content",
+ "position": 30,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "layout": "default",
+ "zones": [
+ {
+ "id": "default_id",
+ "name": "default",
+ "blocks": []
+ }
+ ]
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Landing page"
+ }
+ ]
+ },
+ "fieldSettings": {
+ "availableBlocks": null,
+ "availableLayouts": null,
+ "editorMode": "page_view_mode"
+ },
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example b/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example
new file mode 100644
index 000000000..918783beb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example
@@ -0,0 +1,480 @@
+
+
+
+ 2
+ DEFINED
+ article
+
+ Article
+
+
+ 2002-06-18T09:21:38+00:00
+ 2004-04-20T09:56:29+00:00
+
+
+
+
+ c15b600eb9198b1924063b5a68758232
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 1
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+ 255
+
+
+
+
+ 152
+ short_title
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short title
+
+
+
+
+
+ 255
+
+
+
+
+ 153
+ author
+ ezauthor
+
+ 3
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+ 1
+
+
+
+
+ 120
+ intro
+ ezrichtext
+
+ 4
+ true
+ true
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Intro
+
+
+
+
+
+
+ 121
+ body
+ ezrichtext
+
+ 5
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Body
+
+
+
+
+
+
+ 123
+ enable_comments
+ ezboolean
+
+ 6
+ false
+ false
+ false
+ false
+ false
+
+ Enable comments
+
+
+
+
+
+
+ 154
+ image
+ ezobjectrelation
+
+ 7
+ true
+ false
+ false
+
+
+
+ true
+
+ Image
+
+
+
+ SELECTION_BROWSE
+
+
+
+
+
+
+
+
+ 1
+ DEFINED
+ folder
+
+ Folder
+
+
+ 2002-06-18T09:21:38+00:00
+ 2015-11-29T21:14:32+00:00
+
+
+
+
+ a3d405b81be900468eb153d774f4f0d2
+
+ <short_name|name>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
+
+ 4
+ name
+ ezstring
+
+ 1
+ true
+ true
+ false
+ Folder
+ true
+
+ Name
+
+
+
+
+
+ 255
+
+
+
+
+ 155
+ short_name
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short name
+
+
+
+
+
+ 100
+
+
+
+
+ 119
+ short_description
+ ezrichtext
+
+ 3
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Short description
+
+
+
+
+
+
+ 156
+ description
+ ezrichtext
+
+ 4
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Description
+
+
+
+
+
+
+
+
+ 43
+ DEFINED
+ form
+
+ Form
+
+
+ 2018-09-17T06:46:13+00:00
+ 2018-09-17T06:47:14+00:00
+
+
+
+
+ 6f7f21df775a33c1e4bbc76b48c38476
+
+ <title>
+ false
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 188
+ title
+ ezstring
+ content
+ 1
+ true
+ true
+ false
+
+ true
+
+ Title
+
+
+
+
+
+
+
+
+
+
+ 189
+ form
+ ezform
+ content
+ 2
+ true
+ false
+ false
+
+
+
+
+
+
+ false
+
+ Form
+
+
+
+
+
+
+
+
+ 42
+ DEFINED
+ landing_page
+
+ Landing page
+
+
+
+
+ 2015-07-03T12:00:26+00:00
+ 2015-07-03T12:00:26+00:00
+
+
+
+
+ 60c03e9758465eb69d56b3afb6adf18e
+
+ <name>
+ true
+ eng-GB
+ true
+ PUBLISHED
+ DESC
+
+
+ 185
+ name
+ ezstring
+ content
+ 10
+ true
+ true
+ false
+
+ true
+
+ Title
+
+
+ Title
+
+
+
+
+
+
+
+
+
+ 186
+ description
+ ezstring
+ content
+ 20
+ true
+ true
+ false
+
+ true
+
+ Description
+
+
+ Landing page description
+
+
+
+
+
+
+
+
+
+ 187
+ page
+ ezlandingpage
+ content
+ 30
+ true
+ false
+ false
+
+ default
+
+
+ default_id
+ default
+
+
+
+ false
+
+ Landing page
+
+
+ Landing page
+
+
+
+
+ page_view_mode
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.json.example
new file mode 100644
index 000000000..67593935b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.json.example
@@ -0,0 +1,303 @@
+{
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2",
+ "id": 2,
+ "status": "DEFINED",
+ "identifier": "article",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Article"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2021-06-28T11:31:22+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/2/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft"
+ },
+ "remoteId": "c15b600eb9198b1924063b5a68758232",
+ "urlAliasSchema": "",
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": false,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC",
+ "FieldDefinitions": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinitionList+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions",
+ "FieldDefinition": [
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/1",
+ "id": 1,
+ "identifier": "title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 1,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": "New article",
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/152",
+ "id": 152,
+ "identifier": "short_title",
+ "fieldType": "ezstring",
+ "fieldGroup": "",
+ "position": 2,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": null,
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Short title"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": {
+ "StringLengthValidator": {
+ "maxStringLength": 255,
+ "minStringLength": null
+ }
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/153",
+ "id": 153,
+ "identifier": "author",
+ "fieldType": "ezauthor",
+ "fieldGroup": "",
+ "position": 3,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": [],
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Author"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": {
+ "defaultAuthor": 1
+ },
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/120",
+ "id": 120,
+ "identifier": "intro",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 4,
+ "isTranslatable": true,
+ "isRequired": true,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Intro"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/121",
+ "id": 121,
+ "identifier": "body",
+ "fieldType": "ezrichtext",
+ "fieldGroup": "",
+ "position": 5,
+ "isTranslatable": true,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "xml": "\n\n",
+ "xhtml5edit": "\n\n"
+ },
+ "isSearchable": true,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Body"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/123",
+ "id": 123,
+ "identifier": "enable_comments",
+ "fieldType": "ezboolean",
+ "fieldGroup": "",
+ "position": 6,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": false,
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Enable comments"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/195",
+ "id": 195,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.xml.example
new file mode 100644
index 000000000..59ea81432
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.xml.example
@@ -0,0 +1,182 @@
+
+
+ 2
+ DEFINED
+ article
+
+ Article
+
+
+ 2002-06-18T11:21:38+02:00
+ 2004-04-20T11:56:29+02:00
+
+
+
+
+ c15b600eb9198b1924063b5a68758232
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 1
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+ 255
+
+
+
+
+ 152
+ short_title
+ ezstring
+
+ 2
+ true
+ false
+ false
+
+ true
+
+ Short title
+
+
+
+
+
+ 255
+
+
+
+
+ 153
+ author
+ ezauthor
+
+ 3
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+ 1
+
+
+
+
+ 120
+ intro
+ ezrichtext
+
+ 4
+ true
+ true
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Intro
+
+
+
+
+
+
+ 121
+ body
+ ezrichtext
+
+ 5
+ true
+ false
+ false
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<section xmlns="http://ibexa.co/namespaces/ezpublish5/xhtml5/edit"/>
+
+
+ true
+
+ Body
+
+
+
+
+
+
+ 123
+ enable_comments
+ ezboolean
+
+ 6
+ false
+ false
+ false
+ false
+ false
+
+ Enable comments
+
+
+
+
+
+
+ 154
+ image
+ ezobjectrelation
+
+ 7
+ true
+ false
+ false
+
+
+
+ true
+
+ Image
+
+
+
+ SELECTION_BROWSE
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.json.example
new file mode 100644
index 000000000..6abf1d5bd
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.json.example
@@ -0,0 +1,46 @@
+{
+ "ContentTypeInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfo+json",
+ "_href": "/api/ibexa/v2/content/types/1/draft",
+ "id": 1,
+ "status": "DRAFT",
+ "identifier": "folder",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Folder"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": []
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2021-08-11T11:17:58+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/1/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/1/draft"
+ },
+ "remoteId": "a3d405b81be900468eb153d774f4f0d2",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.xml.example
new file mode 100644
index 000000000..ce2a73a08
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeInfo.xml.example
@@ -0,0 +1,24 @@
+
+
+ 3
+ DRAFT
+ user_group
+
+ User group
+
+
+ 2002-06-18T11:21:38+02:00
+ 2019-02-25T14:41:53+01:00
+
+
+
+
+ 25b4268cdcd01921b808a0d854b877ef
+
+ <name>
+ true
+ eng-GB
+ true
+ PATH
+ ASC
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.json.example
new file mode 100644
index 000000000..bd7dd507e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.json.example
@@ -0,0 +1,6 @@
+{
+ "ContentTypeUpdate": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeUpdate",
+ "defaultAlwaysAvailable": "true"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.xml.example
new file mode 100644
index 000000000..9e9d31ba7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.xml.example
@@ -0,0 +1,4 @@
+
+
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.json.example
new file mode 100644
index 000000000..6b12d0c7b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.json.example
@@ -0,0 +1,51 @@
+{
+ "ContentTypeInfo": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeInfo+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft",
+ "id": 2,
+ "status": "DRAFT",
+ "identifier": "article",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Updated content type name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "This is an updated content type description"
+ }
+ ]
+ },
+ "creationDate": "2002-06-18T09:21:38+00:00",
+ "modificationDate": "2021-08-11T11:58:24+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Modifier": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/types/2/groups"
+ },
+ "Draft": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/2/draft"
+ },
+ "remoteId": "c15b600eb9198b1924063b5a68758232",
+ "urlAliasSchema": null,
+ "nameSchema": "",
+ "isContainer": true,
+ "mainLanguageCode": "eng-GB",
+ "defaultAlwaysAvailable": true,
+ "defaultSortField": "PATH",
+ "defaultSortOrder": "ASC"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.xml.example
new file mode 100644
index 000000000..a96fbd1d8
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.xml.example
@@ -0,0 +1,26 @@
+
+
+ 14
+ DRAFT
+ new_content_type
+
+ Updated content type name
+
+
+ This is an updated content type description
+
+ 2019-02-06T10:56:36+01:00
+ 2019-02-25T12:15:51+01:00
+
+
+
+
+ d7ae816f22fe929e67a359a2ef6e7cde
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.json.example
new file mode 100644
index 000000000..8e9377267
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.json.example
@@ -0,0 +1,21 @@
+{
+ "ContentTypeUpdate": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeUpdate",
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Updated content type name"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "This is an updated content type description"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.xml.example
new file mode 100644
index 000000000..675fdf951
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeUpdate.xml.example
@@ -0,0 +1,9 @@
+
+
+
+ Updated content type name
+
+
+ This is an updated content type description
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example
new file mode 100644
index 000000000..2edf26ace
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example
@@ -0,0 +1,50 @@
+
+
+ 14
+ DEFINED
+ copy_of_article_14
+
+ Updated content type name
+
+
+ This is an updated content type description
+
+ 2019-02-06T10:56:36+01:00
+ 2019-02-25T12:15:51+01:00
+
+
+
+
+ d7ae816f22fe929e67a359a2ef6e7cde
+
+ <short_title|title>
+ true
+ eng-GB
+ false
+ PATH
+ ASC
+
+
+ 188
+ title
+ ezstring
+
+ 1
+ true
+ true
+ false
+ New article
+ true
+
+ Title
+
+
+
+
+
+ 255
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinition.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinition.xml.example
new file mode 100644
index 000000000..e994eb0f5
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinition.xml.example
@@ -0,0 +1,22 @@
+
+
+ 221
+ name2
+ ezstring
+
+ 0
+ true
+ true
+ false
+
+ true
+
+
+
+
+
+ 32
+ 8
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinitionCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinitionCreate.xml.example
new file mode 100644
index 000000000..3282099a8
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinitionCreate.xml.example
@@ -0,0 +1,12 @@
+
+
+ name
+ ezstring
+ true
+
+
+ 32
+ 8
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.json.example
new file mode 100644
index 000000000..df7975cd9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.json.example
@@ -0,0 +1,38 @@
+{
+ "FieldDefinition": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/195",
+ "id": 195,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.xml.example
new file mode 100644
index 000000000..f61269499
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/GET/FieldDefinition.xml.example
@@ -0,0 +1,25 @@
+
+
+ 195
+ image
+ ezimageasset
+ content
+ 7
+ false
+ false
+ false
+
+
+
+
+
+ false
+
+ Image
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinition.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinition.xml.example
new file mode 100644
index 000000000..a941520fe
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinition.xml.example
@@ -0,0 +1,21 @@
+
+
+ 197
+ author
+ ezauthor
+ new_field_group
+ 10
+ true
+ false
+ false
+
+ false
+
+ Author
+
+
+
+ 1
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinitionUpdate.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinitionUpdate.xml.example
new file mode 100644
index 000000000..c1f333a86
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinitionUpdate.xml.example
@@ -0,0 +1,5 @@
+
+
+ new_field_group
+ 10
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example
new file mode 100644
index 000000000..df7975cd9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example
@@ -0,0 +1,38 @@
+{
+ "FieldDefinition": {
+ "_media-type": "application/vnd.ibexa.api.FieldDefinition+json",
+ "_href": "/api/ibexa/v2/content/types/2/fieldDefinitions/195",
+ "id": 195,
+ "identifier": "image",
+ "fieldType": "ezimageasset",
+ "fieldGroup": "content",
+ "position": 7,
+ "isTranslatable": false,
+ "isRequired": false,
+ "isInfoCollector": false,
+ "defaultValue": {
+ "destinationContentId": null,
+ "alternativeText": null,
+ "source": null
+ },
+ "isSearchable": false,
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Image"
+ }
+ ]
+ },
+ "descriptions": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": null
+ }
+ ]
+ },
+ "fieldSettings": [],
+ "validatorConfiguration": []
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example
new file mode 100644
index 000000000..f61269499
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example
@@ -0,0 +1,25 @@
+
+
+ 195
+ image
+ ezimageasset
+ content
+ 7
+ false
+ false
+ false
+
+
+
+
+
+ false
+
+ Image
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.json.example
new file mode 100644
index 000000000..44c021757
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.json.example
@@ -0,0 +1,12 @@
+{
+ "ContentTypeGroupRefList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/2/types",
+ "ContentTypeGroupRef": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.xml.example
new file mode 100644
index 000000000..5f6bef747
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/GET/ContentTypeGroupRefList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/POST/ContentTypeGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/POST/ContentTypeGroupRefList.xml.example
new file mode 100644
index 000000000..b14ad38b7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/POST/ContentTypeGroupRefList.xml.example
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example
new file mode 100644
index 000000000..74fbb967f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example
@@ -0,0 +1,24 @@
+{
+ "ContentTypeGroupRefList": {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroupRefList+json",
+ "_href": "/api/ibexa/v2/content/typegroups/2/types",
+ "ContentTypeGroupRef": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/1",
+ "unlink": {
+ "_href": "/api/ibexa/v2/content/types/2/groups/1",
+ "_method": "DELETE"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ContentTypeGroup+json",
+ "_href": "/api/ibexa/v2/content/typegroups/2",
+ "unlink": {
+ "_href": "/api/ibexa/v2/content/types/2/groups/2",
+ "_method": "DELETE"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example
new file mode 100644
index 000000000..cd216a5ed
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.json.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.json.example
new file mode 100644
index 000000000..40008fd0f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.json.example
@@ -0,0 +1,12 @@
+{
+ "UrlAliasRefList": {
+ "_media-type": "application/vnd.ibexa.api.UrlAliasRefList+json",
+ "_href": "/api/ibexa/v2/content/urlaliases",
+ "UrlAlias": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UrlAlias+json",
+ "_href": "/api/ibexa/v2/content/urlaliases/0-2cecdff5f90b8595d76b68c417b09f36"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.xml.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.xml.example
new file mode 100644
index 000000000..2c7e90a83
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.json.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.json.example
new file mode 100644
index 000000000..078382871
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.json.example
@@ -0,0 +1,15 @@
+{
+ "UrlAlias": {
+ "_media-type": "application/vnd.ibexa.api.UrlAlias+json",
+ "_href": "/api/ibexa/v2/content/urlaliases/0-f530173ad554787c1fe30dc929d98360",
+ "_id": "0-f530173ad554787c1fe30dc929d98360",
+ "_type": "RESOURCE",
+ "resource": "content/view/full",
+ "path": "/example-global",
+ "languageCodes": "eng-GB",
+ "alwaysAvailable": true,
+ "isHistory": false,
+ "forward": true,
+ "custom": true
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.xml.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.xml.example
new file mode 100644
index 000000000..2eca610bc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAlias.xml.example
@@ -0,0 +1,10 @@
+
+
+
+ /example-urlalias
+ eng-GB
+ true
+ false
+ true
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.json.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.json.example
new file mode 100644
index 000000000..0eb520514
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.json.example
@@ -0,0 +1,10 @@
+{
+ "UrlAliasCreate": {
+ "_type": "GLOBAL",
+ "resource": "module:content/view/full",
+ "path": "example-global",
+ "languageCode": "eng-GB",
+ "alwaysAvailable": "true",
+ "forward": "true"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.xml.example
new file mode 100644
index 000000000..218ab60ec
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.xml.example
@@ -0,0 +1,8 @@
+
+
+
+ example-global
+ eng-GB
+ true
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.json.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.json.example
new file mode 100644
index 000000000..9fe37c238
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.json.example
@@ -0,0 +1,15 @@
+{
+ "UrlAlias": {
+ "_media-type": "application/vnd.ibexa.api.UrlAlias+json",
+ "_href": "/api/ibexa/v2/content/urlaliases/0-2cecdff5f90b8595d76b68c417b09f36",
+ "_id": "0-2cecdff5f90b8595d76b68c417b09f36",
+ "_type": "RESOURCE",
+ "resource": "content/view/full",
+ "path": "/example-global",
+ "languageCodes": "eng-GB",
+ "alwaysAvailable": true,
+ "isHistory": false,
+ "forward": true,
+ "custom": true
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.xml.example b/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.xml.example
new file mode 100644
index 000000000..565b070ef
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.xml.example
@@ -0,0 +1,10 @@
+
+
+ content/view/full
+ /example-global
+ eng-GB
+ true
+ false
+ true
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.json.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.json.example
new file mode 100644
index 000000000..c8e1bbefc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.json.example
@@ -0,0 +1,16 @@
+{
+ "UrlWildcardList": {
+ "_media-type": "application/vnd.ibexa.api.UrlWildcardList+json",
+ "_href": "/api/ibexa/v2/content/urlwildcards",
+ "UrlWildcard": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UrlWildcard+json",
+ "_href": "/api/ibexa/v2/content/urlwildcards/1",
+ "_id": 1,
+ "sourceUrl": "/api/ibexa/v2/content/location/2",
+ "destinationUrl": "/api/ibexa/v2/content/location/59",
+ "forward": true
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.xml.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.xml.example
new file mode 100644
index 000000000..6ca3442d9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.xml.example
@@ -0,0 +1,8 @@
+
+
+
+ /api/ibexa/v2/content/location/2
+ /api/ibexa/v2/content/location/59
+ true
+
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.json.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.json.example
new file mode 100644
index 000000000..1bef2daff
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.json.example
@@ -0,0 +1,10 @@
+{
+ "UrlWildcard": {
+ "_media-type": "application/vnd.ibexa.api.UrlWildcard+json",
+ "_href": "/api/ibexa/v2/content/urlwildcards/6",
+ "_id": 6,
+ "sourceUrl": "/api/ibexa/v2/content/location/2",
+ "destinationUrl": "/api/ibexa/v2/content/location/59",
+ "forward": true
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.xml.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.xml.example
new file mode 100644
index 000000000..34e7bee41
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcard.xml.example
@@ -0,0 +1,6 @@
+
+
+ /api/ibexa/v2/content/location/2
+ /api/ibexa/v2/content/location/59
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.json.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.json.example
new file mode 100644
index 000000000..0bc4c24da
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.json.example
@@ -0,0 +1,7 @@
+{
+ "URLWildcardCreate": {
+ "sourceUrl": "/api/ibexa/v2/content/location/2",
+ "destinationUrl": "/api/ibexa/v2/content/location/59",
+ "forward": true
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.xml.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.xml.example
new file mode 100644
index 000000000..a77f9f13f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.xml.example
@@ -0,0 +1,6 @@
+
+
+ /api/ibexa/v2/content/location/2
+ /api/ibexa/v2/content/location/59
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.json.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.json.example
new file mode 100644
index 000000000..f51ac49b1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.json.example
@@ -0,0 +1,10 @@
+{
+ "UrlWildcard": {
+ "_media-type": "application/vnd.ibexa.api.UrlWildcard+json",
+ "_href": "/api/ibexa/v2/content/urlwildcards/4",
+ "_id": 4,
+ "sourceUrl": "/api/ibexa/v2/content/location/2",
+ "destinationUrl": "/api/ibexa/v2/content/location/59",
+ "forward": true
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.xml.example b/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.xml.example
new file mode 100644
index 000000000..b4830abe8
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.xml.example
@@ -0,0 +1,6 @@
+
+
+ /api/ibexa/v2/content/location/2
+ /api/ibexa/v2/content/location/59
+ true
+
diff --git a/src/bundle/Resources/api_platform/examples/services/countries/GET/CountriesList.xml.example b/src/bundle/Resources/api_platform/examples/services/countries/GET/CountriesList.xml.example
new file mode 100644
index 000000000..374c6aa36
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/services/countries/GET/CountriesList.xml.example
@@ -0,0 +1,1479 @@
+
+
+
+ Afghanistan
+ AF
+ AFG
+ 93
+
+
+ Ã…land
+ AX
+ ALA
+ 358
+
+
+ Albania
+ AL
+ ALB
+ 355
+
+
+ Algeria
+ DZ
+ DZA
+ 213
+
+
+ American Samoa
+ AS
+ ASM
+ 1684
+
+
+ Andorra
+ AD
+ AND
+ 376
+
+
+ Angola
+ AO
+ AGO
+ 244
+
+
+ Anguilla
+ AI
+ AIA
+ 1264
+
+
+ Antarctica
+ AQ
+ ATA
+ 672
+
+
+ Antigua and Barbuda
+ AG
+ ATG
+ 1268
+
+
+ Argentina
+ AR
+ ARG
+ 54
+
+
+ Armenia
+ AM
+ ARM
+ 374
+
+
+ Aruba
+ AW
+ ABW
+ 297
+
+
+ Australia
+ AU
+ AUS
+ 61
+
+
+ Austria
+ AT
+ AUT
+ 43
+
+
+ Azerbaijan
+ AZ
+ AZE
+ 994
+
+
+ Bahamas
+ BS
+ BHS
+ 1242
+
+
+ Bahrain
+ BH
+ BHR
+ 973
+
+
+ Bangladesh
+ BD
+ BGD
+ 880
+
+
+ Barbados
+ BB
+ BRB
+ 1246
+
+
+ Belarus
+ BY
+ BLR
+ 375
+
+
+ Belgium
+ BE
+ BEL
+ 32
+
+
+ Belize
+ BZ
+ BLZ
+ 501
+
+
+ Benin
+ BJ
+ BEN
+ 229
+
+
+ Bermuda
+ BM
+ BMU
+ 1441
+
+
+ Bhutan
+ BT
+ BTN
+ 975
+
+
+ Bolivia
+ BO
+ BOL
+ 591
+
+
+ Bosnia and Herzegovina
+ BA
+ BIH
+ 387
+
+
+ Botswana
+ BW
+ BWA
+ 267
+
+
+ Bouvet Island
+ BV
+ BVT
+ 47
+
+
+ Brazil
+ BR
+ BRA
+ 55
+
+
+ British Indian Ocean Territory
+ IO
+ IOT
+ 246
+
+
+ Brunei Darussalam
+ BN
+ BRN
+ 673
+
+
+ Bulgaria
+ BG
+ BGR
+ 359
+
+
+ Burkina Faso
+ BF
+ BFA
+ 226
+
+
+ Burundi
+ BI
+ BDI
+ 257
+
+
+ Cambodia
+ KH
+ KHM
+ 855
+
+
+ Cameroon
+ CM
+ CMR
+ 237
+
+
+ Canada
+ CA
+ CAN
+ 1
+
+
+ Cape Verde
+ CV
+ CPV
+ 238
+
+
+ Cayman Islands
+ KY
+ CYM
+ 1345
+
+
+ Central African Republic
+ CF
+ CAF
+ 236
+
+
+ Chad
+ TD
+ TCD
+ 235
+
+
+ Chile
+ CL
+ CHL
+ 56
+
+
+ China
+ CN
+ CHN
+ 86
+
+
+ Christmas Island
+ CX
+ CXR
+ 61
+
+
+ Cocos (Keeling) Islands
+ CC
+ CCK
+ 61
+
+
+ Colombia
+ CO
+ COL
+ 57
+
+
+ Comoros
+ KM
+ COM
+ 269
+
+
+ Congo
+ CG
+ COG
+ 242
+
+
+ Congo, The Democratic Republic Of The
+ CD
+ COD
+ 243
+
+
+ Cook Islands
+ CK
+ COK
+ 682
+
+
+ Costa Rica
+ CR
+ CRI
+ 506
+
+
+ Côte d'Ivoire
+ CI
+ CIV
+ 225
+
+
+ Croatia
+ HR
+ HRV
+ 385
+
+
+ Cuba
+ CU
+ CUB
+ 53
+
+
+ Cyprus
+ CY
+ CYP
+ 357
+
+
+ Czech Republic
+ CZ
+ CZE
+ 420
+
+
+ Denmark
+ DK
+ DNK
+ 45
+
+
+ Djibouti
+ DJ
+ DJI
+ 253
+
+
+ Dominica
+ DM
+ DMA
+ 1767
+
+
+ Dominican Republic
+ DO
+ DOM
+ 1809
+
+
+ Ecuador
+ EC
+ ECU
+ 593
+
+
+ Egypt
+ EG
+ EGY
+ 20
+
+
+ El Salvador
+ SV
+ SLV
+ 503
+
+
+ Equatorial Guinea
+ GQ
+ GNQ
+ 240
+
+
+ Eritrea
+ ER
+ ERI
+ 291
+
+
+ Estonia
+ EE
+ EST
+ 372
+
+
+ Ethiopia
+ ET
+ ETH
+ 251
+
+
+ Falkland Islands (Malvinas)
+ FK
+ FLK
+ 500
+
+
+ Faroe Islands
+ FO
+ FRO
+ 298
+
+
+ Fiji
+ FJ
+ FJI
+ 679
+
+
+ Finland
+ FI
+ FIN
+ 358
+
+
+ France
+ FR
+ FRA
+ 33
+
+
+ French Guiana
+ GF
+ GUF
+ 594
+
+
+ French Polynesia
+ PF
+ PYF
+ 689
+
+
+ French Southern Territories
+ TF
+ ATF
+ 0
+
+
+ Gabon
+ GA
+ GAB
+ 241
+
+
+ Gambia
+ GM
+ GMB
+ 220
+
+
+ Georgia
+ GE
+ GEO
+ 995
+
+
+ Germany
+ DE
+ DEU
+ 49
+
+
+ Ghana
+ GH
+ GHA
+ 233
+
+
+ Gibraltar
+ GI
+ GIB
+ 350
+
+
+ Greece
+ GR
+ GRC
+ 30
+
+
+ Greenland
+ GL
+ GRL
+ 299
+
+
+ Grenada
+ GD
+ GRD
+ 1473
+
+
+ Guadeloupe
+ GP
+ GLP
+ 590
+
+
+ Guam
+ GU
+ GUM
+ 1671
+
+
+ Guatemala
+ GT
+ GTM
+ 502
+
+
+ Guernsey
+ GG
+ GGY
+ 44
+
+
+ Guinea
+ GN
+ GIN
+ 224
+
+
+ Guinea-Bissau
+ GW
+ GNB
+ 245
+
+
+ Guyana
+ GY
+ GUY
+ 592
+
+
+ Haiti
+ HT
+ HTI
+ 509
+
+
+ Heard Island and McDonald Islands
+ HM
+ HMD
+ 672
+
+
+ Honduras
+ HN
+ HND
+ 504
+
+
+ Hong Kong
+ HK
+ HKG
+ 852
+
+
+ Hungary
+ HU
+ HUN
+ 36
+
+
+ Iceland
+ IS
+ ISL
+ 354
+
+
+ India
+ IN
+ IND
+ 91
+
+
+ Indonesia
+ ID
+ IDN
+ 62
+
+
+ Iran, Islamic Republic of
+ IR
+ IRN
+ 98
+
+
+ Iraq
+ IQ
+ IRQ
+ 964
+
+
+ Ireland
+ IE
+ IRL
+ 353
+
+
+ Isle of Man
+ IM
+ IMN
+ 44
+
+
+ Israel
+ IL
+ ISR
+ 972
+
+
+ Italy
+ IT
+ ITA
+ 39
+
+
+ Jamaica
+ JM
+ JAM
+ 1876
+
+
+ Japan
+ JP
+ JPN
+ 81
+
+
+ Jersey
+ JE
+ JEY
+ 44
+
+
+ Jordan
+ JO
+ JOR
+ 962
+
+
+ Kazakhstan
+ KZ
+ KAZ
+ 7
+
+
+ Kenya
+ KE
+ KEN
+ 254
+
+
+ Kiribati
+ KI
+ KIR
+ 686
+
+
+ Korea, Democratic People's Republic of
+ KP
+ PRK
+ 850
+
+
+ Korea, Republic of
+ KR
+ KOR
+ 82
+
+
+ Kuwait
+ KW
+ KWT
+ 965
+
+
+ Kyrgyzstan
+ KG
+ KGZ
+ 996
+
+
+ Lao People's Democratic Republic
+ LA
+ LAO
+ 856
+
+
+ Latvia
+ LV
+ LVA
+ 371
+
+
+ Lebanon
+ LB
+ LBN
+ 961
+
+
+ Lesotho
+ LS
+ LSO
+ 266
+
+
+ Liberia
+ LR
+ LBR
+ 231
+
+
+ Libyan Arab Jamahiriya
+ LY
+ LBY
+ 218
+
+
+ Liechtenstein
+ LI
+ LIE
+ 423
+
+
+ Lithuania
+ LT
+ LTU
+ 370
+
+
+ Luxembourg
+ LU
+ LUX
+ 352
+
+
+ Macau
+ MO
+ MAC
+ 853
+
+
+ Macedonia, The Former Yugoslav Republic of
+ MK
+ MKD
+ 389
+
+
+ Madagascar
+ MG
+ MDG
+ 261
+
+
+ Malawi
+ MW
+ MWI
+ 265
+
+
+ Malaysia
+ MY
+ MYS
+ 60
+
+
+ Maldives
+ MV
+ MDV
+ 960
+
+
+ Mali
+ ML
+ MLI
+ 223
+
+
+ Malta
+ MT
+ MLT
+ 356
+
+
+ Marshall Islands
+ MH
+ MHL
+ 692
+
+
+ Martinique
+ MQ
+ MTQ
+ 596
+
+
+ Mauritania
+ MR
+ MRT
+ 222
+
+
+ Mauritius
+ MU
+ MUS
+ 230
+
+
+ Mayotte
+ YT
+ MYT
+ 262
+
+
+ Mexico
+ MX
+ MEX
+ 52
+
+
+ Micronesia, Federated States of
+ FM
+ FSM
+ 691
+
+
+ Moldova, Republic of
+ MD
+ MDA
+ 373
+
+
+ Monaco
+ MC
+ MCO
+ 377
+
+
+ Mongolia
+ MN
+ MNG
+ 976
+
+
+ Montenegro
+ ME
+ MNE
+ 382
+
+
+ Montserrat
+ MS
+ MSR
+ 1664
+
+
+ Morocco
+ MA
+ MAR
+ 212
+
+
+ Mozambique
+ MZ
+ MOZ
+ 258
+
+
+ Myanmar
+ MM
+ MMR
+ 95
+
+
+ Namibia
+ NA
+ NAM
+ 264
+
+
+ Nauru
+ NR
+ NRU
+ 674
+
+
+ Nepal
+ NP
+ NPL
+ 977
+
+
+ Netherlands
+ NL
+ NLD
+ 31
+
+
+ Netherlands Antilles
+ AN
+ ANT
+ 599
+
+
+ New Caledonia
+ NC
+ NCL
+ 687
+
+
+ New Zealand
+ NZ
+ NZL
+ 64
+
+
+ Nicaragua
+ NI
+ NIC
+ 505
+
+
+ Niger
+ NE
+ NER
+ 227
+
+
+ Nigeria
+ NG
+ NGA
+ 234
+
+
+ Niue
+ NU
+ NIU
+ 683
+
+
+ Norfolk Island
+ NF
+ NFK
+ 6723
+
+
+ Northern Mariana Islands
+ MP
+ MNP
+ 1670
+
+
+ Norway
+ NO
+ NOR
+ 47
+
+
+ Oman
+ OM
+ OMN
+ 968
+
+
+ Pakistan
+ PK
+ PAK
+ 92
+
+
+ Palau
+ PW
+ PLW
+ 680
+
+
+ Palestinian Territory, Occupied
+ PS
+ PSE
+ 970
+
+
+ Panama
+ PA
+ PAN
+ 507
+
+
+ Papua New Guinea
+ PG
+ PNG
+ 675
+
+
+ Paraguay
+ PY
+ PRY
+ 595
+
+
+ Peru
+ PE
+ PER
+ 51
+
+
+ Philippines
+ PH
+ PHL
+ 63
+
+
+ Pitcairn
+ PN
+ PCN
+ 64
+
+
+ Poland
+ PL
+ POL
+ 48
+
+
+ Portugal
+ PT
+ PRT
+ 351
+
+
+ Puerto Rico
+ PR
+ PRI
+ 1787
+
+
+ Qatar
+ QA
+ QAT
+ 974
+
+
+ Reunion
+ RE
+ REU
+ 262
+
+
+ Romania
+ RO
+ ROU
+ 40
+
+
+ Russian Federation
+ RU
+ RUS
+ 7
+
+
+ Rwanda
+ RW
+ RWA
+ 250
+
+
+ Saint Barthélemy
+ BL
+ BLM
+ 590
+
+
+ Saint Helena
+ SH
+ SHN
+ 290
+
+
+ Saint Kitts and Nevis
+ KN
+ KNA
+ 1869
+
+
+ Saint Lucia
+ LC
+ LCA
+ 1758
+
+
+ Saint Martin
+ MF
+ MAF
+ 590
+
+
+ Saint Pierre and Miquelon
+ PM
+ SPM
+ 508
+
+
+ Saint Vincent and The Grenadines
+ VC
+ VCT
+ 1784
+
+
+ Samoa
+ WS
+ WSM
+ 685
+
+
+ San Marino
+ SM
+ SMR
+ 378
+
+
+ Sao Tome and Principe
+ ST
+ STP
+ 239
+
+
+ Saudi Arabia
+ SA
+ SAU
+ 966
+
+
+ Senegal
+ SN
+ SEN
+ 221
+
+
+ Serbia
+ RS
+ SRB
+ 381
+
+
+ Seychelles
+ SC
+ SYC
+ 248
+
+
+ Sierra Leone
+ SL
+ SLE
+ 232
+
+
+ Singapore
+ SG
+ SGP
+ 65
+
+
+ Slovakia
+ SK
+ SVK
+ 421
+
+
+ Slovenia
+ SI
+ SVN
+ 386
+
+
+ Solomon Islands
+ SB
+ SLB
+ 677
+
+
+ Somalia
+ SO
+ SOM
+ 252
+
+
+ South Africa
+ ZA
+ ZAF
+ 27
+
+
+ South Georgia and The South Sandwich Islands
+ GS
+ SGS
+ 500
+
+
+ Spain
+ ES
+ ESP
+ 34
+
+
+ Sri Lanka
+ LK
+ LKA
+ 94
+
+
+ Sudan
+ SD
+ SDN
+ 249
+
+
+ Suriname
+ SR
+ SUR
+ 597
+
+
+ Svalbard and Jan Mayen
+ SJ
+ SJM
+ 47
+
+
+ Swaziland
+ SZ
+ SWZ
+ 268
+
+
+ Sweden
+ SE
+ SWE
+ 46
+
+
+ Switzerland
+ CH
+ CHE
+ 41
+
+
+ Syrian Arab Republic
+ SY
+ SYR
+ 963
+
+
+ Taiwan
+ TW
+ TWN
+ 886
+
+
+ Tajikistan
+ TJ
+ TJK
+ 992
+
+
+ Tanzania, United Republic of
+ TZ
+ TZA
+ 255
+
+
+ Thailand
+ TH
+ THA
+ 66
+
+
+ Timor-Leste
+ TL
+ TLS
+ 670
+
+
+ Togo
+ TG
+ TGO
+ 228
+
+
+ Tokelau
+ TK
+ TKL
+ 690
+
+
+ Tonga
+ TO
+ TON
+ 676
+
+
+ Trinidad and Tobago
+ TT
+ TTO
+ 1868
+
+
+ Tunisia
+ TN
+ TUN
+ 216
+
+
+ Turkey
+ TR
+ TUR
+ 90
+
+
+ Turkmenistan
+ TM
+ TKM
+ 993
+
+
+ Turks and Caicos Islands
+ TC
+ TCA
+ 1649
+
+
+ Tuvalu
+ TV
+ TUV
+ 688
+
+
+ Uganda
+ UG
+ UGA
+ 256
+
+
+ Ukraine
+ UA
+ UKR
+ 380
+
+
+ United Arab Emirates
+ AE
+ ARE
+ 971
+
+
+ United Kingdom
+ GB
+ GBR
+ 44
+
+
+ United States Minor Outlying Islands
+ UM
+ UMI
+ 1
+
+
+ United States of America
+ US
+ USA
+ 1
+
+
+ Uruguay
+ UY
+ URY
+ 598
+
+
+ Uzbekistan
+ UZ
+ UZB
+ 998
+
+
+ Vanuatu
+ VU
+ VUT
+ 678
+
+
+ Holy See (Vatican City State)
+ VA
+ VAT
+ 3906
+
+
+ Venezuela
+ VE
+ VEN
+ 58
+
+
+ Viet Nam
+ VN
+ VNM
+ 84
+
+
+ Virgin Islands, British
+ VG
+ VGB
+ 1284
+
+
+ Virgin Islands, U.S.
+ VI
+ VIR
+ 1340
+
+
+ Wallis and Futuna
+ WF
+ WLF
+ 681
+
+
+ Western Sahara
+ EH
+ ESH
+ 212
+
+
+ Yemen
+ YE
+ YEM
+ 967
+
+
+ Zambia
+ ZM
+ ZMB
+ 260
+
+
+ Zimbabwe
+ ZW
+ ZWE
+ 263
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.json.example
new file mode 100644
index 000000000..afe640263
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.json.example
@@ -0,0 +1,156 @@
+{
+ "UserGroupList": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/groups",
+ "UserGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/15",
+ "_id": 14,
+ "_remoteId": "1bb4fe25487f05527efa8bfd394cecc7",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4"
+ },
+ "name": "Administrator User",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/13/15"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2002-10-06T16:13:50+00:00",
+ "lastModificationDate": "2011-03-25T14:07:04+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions/3",
+ "VersionInfo": {
+ "id": 499,
+ "versionNo": 3,
+ "status": "PUBLISHED",
+ "modificationDate": "2011-03-25T14:07:04+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2011-03-25T14:03:03+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Administrator User"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/14"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 28,
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Administrator"
+ },
+ {
+ "id": 29,
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "User"
+ },
+ {
+ "id": 30,
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezuser",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 14,
+ "login": "admin",
+ "email": "admin@link.invalid",
+ "passwordUpdatedAt": null,
+ "enabled": true,
+ "maxLogin": 10,
+ "plainPassword": null
+ }
+ },
+ {
+ "id": 178,
+ "fieldDefinitionIdentifier": "signature",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "eztext",
+ "fieldValue": null
+ },
+ {
+ "id": 180,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezimage",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions/3/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "ParentUserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13"
+ },
+ "Subgroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/15/subgroups"
+ },
+ "Users": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/15/users"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/15/roles"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.xml.example
new file mode 100644
index 000000000..a6ea1d93f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.xml.example
@@ -0,0 +1,94 @@
+
+
+
+
+ Administrator User
+
+
+
+
+
+ 2002-10-06T16:13:50+00:00
+ 2011-03-25T14:07:04+00:00
+ eng-GB
+ true
+
+
+ 499
+ 3
+ PUBLISHED
+ 2011-03-25T14:07:04+00:00
+
+ 2011-03-25T14:03:03+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Administrator User
+
+
+
+
+
+ 28
+ first_name
+ eng-GB
+ ezstring
+ Administrator
+
+
+ 29
+ last_name
+ eng-GB
+ ezstring
+ User
+
+
+ 30
+ user_account
+ eng-GB
+ ezuser
+
+ true
+ 14
+ admin
+ admin@link.invalid
+
+ true
+ 10
+
+
+
+
+ 178
+ signature
+ eng-GB
+ eztext
+
+
+
+ 180
+ image
+ eng-GB
+ ezimage
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.json.example
new file mode 100644
index 000000000..56b569809
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.json.example
@@ -0,0 +1,12 @@
+{
+ "UserGroupRefList": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/groups/13/subgroups",
+ "UserGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/112"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.xml.example
new file mode 100644
index 000000000..2ec89ff11
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/id/subgroups/GET/UserGroupRefList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.json.example
new file mode 100644
index 000000000..1df6338d7
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.json.example
@@ -0,0 +1,16 @@
+{
+ "UserRefList": {
+ "_media-type": "application/vnd.ibexa.api.UserRefList+json",
+ "_href": "/api/ibexa/v2/user/groups/13/users",
+ "User": [
+ {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/113"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.xml.example
new file mode 100644
index 000000000..633e04a03
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.xml.example
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.json.example
new file mode 100644
index 000000000..56f81323a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.json.example
@@ -0,0 +1,120 @@
+{
+ "UserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13",
+ "_id": 12,
+ "_remoteId": "9b47a45624b023b1a76c73b74d704acf",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/3"
+ },
+ "name": "Administrator users",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/13"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2002-10-06T16:12:55+00:00",
+ "lastModificationDate": "2002-10-06T16:12:55+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions/1",
+ "VersionInfo": {
+ "id": 440,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2002-10-06T16:12:55+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2002-10-06T16:12:40+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Administrator users"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/12"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 24,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Administrator users"
+ },
+ {
+ "id": 25,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user_group",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "ParentUserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5"
+ },
+ "Subgroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/subgroups"
+ },
+ "Users": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/users"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/roles"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.xml.example
new file mode 100644
index 000000000..2145db50a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/GET/UserGroup.xml.example
@@ -0,0 +1,62 @@
+
+
+
+ Administrator users
+
+
+
+
+
+ 2002-10-06T16:12:55+00:00
+ 2002-10-06T16:12:55+00:00
+ eng-GB
+ true
+
+
+ 440
+ 1
+ PUBLISHED
+ 2002-10-06T16:12:55+00:00
+
+ 2002-10-06T16:12:40+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Administrator users
+
+
+
+
+
+ 24
+ name
+ eng-GB
+ ezstring
+ Administrator users
+
+
+ 25
+ description
+ eng-GB
+ ezstring
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user_group
+
+
+ image/svg+xml
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.json.example
new file mode 100644
index 000000000..56f81323a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.json.example
@@ -0,0 +1,120 @@
+{
+ "UserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13",
+ "_id": 12,
+ "_remoteId": "9b47a45624b023b1a76c73b74d704acf",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/3"
+ },
+ "name": "Administrator users",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/13"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2002-10-06T16:12:55+00:00",
+ "lastModificationDate": "2002-10-06T16:12:55+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions/1",
+ "VersionInfo": {
+ "id": 440,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2002-10-06T16:12:55+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2002-10-06T16:12:40+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Administrator users"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/12"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 24,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Administrator users"
+ },
+ {
+ "id": 25,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/12/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user_group",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "ParentUserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5"
+ },
+ "Subgroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/subgroups"
+ },
+ "Users": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/users"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13/roles"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.xml.example
new file mode 100644
index 000000000..2145db50a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroup.xml.example
@@ -0,0 +1,62 @@
+
+
+
+ Administrator users
+
+
+
+
+
+ 2002-10-06T16:12:55+00:00
+ 2002-10-06T16:12:55+00:00
+ eng-GB
+ true
+
+
+ 440
+ 1
+ PUBLISHED
+ 2002-10-06T16:12:55+00:00
+
+ 2002-10-06T16:12:40+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Administrator users
+
+
+
+
+
+ 24
+ name
+ eng-GB
+ ezstring
+ Administrator users
+
+
+ 25
+ description
+ eng-GB
+ ezstring
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user_group
+
+
+ image/svg+xml
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.json.example
new file mode 100644
index 000000000..270526545
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.json.example
@@ -0,0 +1,7 @@
+{
+ "UserGroupUpdate":{
+ "Section": {
+ "_href": "/api/ibexa/v2/content/sections/2"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.xml.example
new file mode 100644
index 000000000..1cda91de1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssigmentList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssigmentList.json.example
new file mode 100644
index 000000000..2a429ff57
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssigmentList.json.example
@@ -0,0 +1,10 @@
+{
+ "RoleAssignment": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/groups/1/42/44/roles/1",
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/1"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..4441ea6dd
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/GET/RoleAssignmentList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.json.example
new file mode 100644
index 000000000..027f2d71b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.json.example
@@ -0,0 +1,23 @@
+{
+ "RoleAssignInput": {
+ "Role": {
+ "_href": "/api/ibexa/v2/user/roles/2",
+ "_media-type": "application/vnd.ibexa.api.RoleAssignInput+json"
+ },
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_href": "/api/ibexa/v2/content/sections/1",
+ "_media-type": "application/vnd.ibexa.api.Section+json"
+ },
+ {
+ "_href": "/api/ibexa/v2/content/sections/4",
+ "_media-type": "application/vnd.ibexa.api.Section+json"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.xml.example
new file mode 100644
index 000000000..ddaefdad1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.xml.example
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.json.example
new file mode 100644
index 000000000..4be381050
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.json.example
@@ -0,0 +1,16 @@
+{
+ "RoleAssignmentList": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/12/2/roles",
+ "RoleAssignment": [
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/groups/1/12/2/roles/2",
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..28f7279ec
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignmentList.xml.example
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.json.example
new file mode 100644
index 000000000..98d139c12
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.json.example
@@ -0,0 +1,27 @@
+{
+ "RoleAssignmentList": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/57/58/roles",
+ "RoleAssignment": [
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/groups/1/57/58/roles/3",
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1"
+ }
+ ]
+ }
+ },
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/3"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..5c7da74a6
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/DELETE/RoleAssignmentList.xml.example
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.json.example
new file mode 100644
index 000000000..3db7d95a4
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.json.example
@@ -0,0 +1,10 @@
+{
+ "RoleAssignment": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/groups/1/11/12/roles/1",
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/1"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.xml.example
new file mode 100644
index 000000000..367622000
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/roles/role_id/GET/RoleAssignment.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example
new file mode 100644
index 000000000..ffa7a38f4
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example
@@ -0,0 +1,120 @@
+{
+ "UserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/81",
+ "_id": 87,
+ "_remoteId": "remoteId-qwert098",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/3"
+ },
+ "name": "UserGroup2",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/87/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/81"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/87/locations"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2021-08-09T09:06:49+00:00",
+ "lastModificationDate": "2021-08-09T09:06:49+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/87/versions/1",
+ "VersionInfo": {
+ "id": 578,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2021-08-09T09:06:49+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-08-09T09:06:49+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "UserGroup2"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/87"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 384,
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "UserGroup2"
+ },
+ {
+ "id": 385,
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "This is the description of the user group"
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/87/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user_group",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "ParentUserGroup": {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5"
+ },
+ "Subgroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/81/subgroups"
+ },
+ "Users": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/81/users"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/81/roles"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example
new file mode 100644
index 000000000..7f182f8de
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example
@@ -0,0 +1,62 @@
+
+
+
+ UserGroup2
+
+
+
+
+
+ 2021-08-09T09:03:35+00:00
+ 2021-08-09T09:03:35+00:00
+ eng-GB
+ true
+
+
+ 576
+ 1
+ PUBLISHED
+ 2021-08-09T09:03:35+00:00
+
+ 2021-08-09T09:03:35+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ UserGroup2
+
+
+
+
+
+ 380
+ name
+ eng-GB
+ ezstring
+ UserGroup2
+
+
+ 381
+ description
+ eng-GB
+ ezstring
+ This is the description of the user group
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user_group
+
+
+ image/svg+xml
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.json.example
new file mode 100644
index 000000000..876e65bdf
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.json.example
@@ -0,0 +1,20 @@
+{
+ "UserGroupCreate": {
+ "mainLanguageCode": "eng-GB",
+ "remoteId": "remoteId-qwert098",
+ "fields": {
+ "field": [
+ {
+ "fieldDefinitionIdentifier": "name",
+ "languageCode": "eng-GB",
+ "fieldValue": "UserGroup2"
+ },
+ {
+ "fieldDefinitionIdentifier": "description",
+ "languageCode": "eng-GB",
+ "fieldValue": "This is the description of the user group"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.xml.example
new file mode 100644
index 000000000..2ae0b4aaa
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.xml.example
@@ -0,0 +1,17 @@
+
+
+ eng-GB
+ remoteId-qwert098
+
+
+ name
+ eng-GB
+ UserGroup
+
+
+ description
+ eng-GB
+ This is the description of the user group
+
+
+
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.json.example
new file mode 100644
index 000000000..c0866de65
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.json.example
@@ -0,0 +1,149 @@
+{
+ "User": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/57",
+ "_id": 57,
+ "_remoteId": "remoteId-qwert426",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4"
+ },
+ "name": "Yura Rajzer",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/13/58"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/locations"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/57/groups"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2021-08-11T13:52:13+00:00",
+ "lastModificationDate": "2021-08-11T13:52:13+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/57/versions/1",
+ "VersionInfo": {
+ "id": 517,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2021-08-11T13:52:13+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-08-11T13:52:13+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Yura Rajzer"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/57"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 262,
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Yura"
+ },
+ {
+ "id": 263,
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Rajzer"
+ },
+ {
+ "id": 264,
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezuser",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 57,
+ "login": "yura",
+ "email": "yurarajzer@example.net",
+ "passwordUpdatedAt": 1628689933,
+ "enabled": true,
+ "maxLogin": 0,
+ "plainPassword": null
+ }
+ },
+ {
+ "id": 265,
+ "fieldDefinitionIdentifier": "signature",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "eztext",
+ "fieldValue": null
+ },
+ {
+ "id": 266,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezimage",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/57/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "login": "yura",
+ "email": "yurarajzer@example.net",
+ "enabled": true,
+ "UserGroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/users/57/groups"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/57/roles"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.xml.example
new file mode 100644
index 000000000..bbe48cbe9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/User.xml.example
@@ -0,0 +1,86 @@
+
+
+
+Yura Rajzer
+
+
+
+
+
+
+2019-02-27T11:23:42+01:00
+2019-02-27T11:23:42+01:00
+eng-GB
+true
+
+
+ 515
+ 1
+ PUBLISHED
+ 2019-02-27T11:23:42+01:00
+
+ 2019-02-27T11:23:42+01:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Yura Rajzer
+
+
+
+
+
+ 207
+ first_name
+ eng-GB
+ ezstring
+ Yura
+
+
+ 208
+ last_name
+ eng-GB
+ ezstring
+ Rajzer
+
+
+ 209
+ user_account
+ eng-GB
+ ezuser
+
+ true
+ 59
+ yura
+ yurarajzer@example.net
+ true
+ 0
+
+
+
+ 210
+ signature
+ eng-GB
+ eztext
+
+
+
+ 211
+ image
+ eng-GB
+ ezimage
+
+
+
+
+
+yura
+yurarajzer@example.net
+true
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.json.example b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.json.example
new file mode 100644
index 000000000..d403e5324
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.json.example
@@ -0,0 +1,35 @@
+{
+ "UserCreate": {
+ "mainLanguageCode": "eng-GB",
+ "remoteId": "remoteId-23456789",
+ "login": "johnsmith2",
+ "email": "example@example.com",
+ "password": "Secrepassword5!",
+ "fields": {
+ "field": [
+ {
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldValue": "John"
+ },
+ {
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldValue": "Smith"
+ },
+ {
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 14,
+ "login": "johnsmith",
+ "email": "example@example.com",
+ "enabled": true,
+ "maxLogin": 10
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.xml.example b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.xml.example
new file mode 100644
index 000000000..1c281381e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.xml.example
@@ -0,0 +1,32 @@
+
+
+ eng-GB
+ remoteId-23456789
+ johnsmith
+ example@example.com
+ Secrepassword5!
+
+
+ first_name
+ eng-GB
+ John
+
+
+ last_name
+ eng-GB
+ Smith
+
+
+ user_account
+ eng-GB
+
+ true
+ 14
+ johnsmith
+ example@example.com
+ true
+ 10
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.json.example b/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.json.example
new file mode 100644
index 000000000..05f6b541d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.json.example
@@ -0,0 +1,104 @@
+{
+ "PolicyList": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/policies",
+ "Policy": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/349",
+ "id": 349,
+ "module": "content",
+ "function": "read",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "3"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "6"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/350",
+ "id": 350,
+ "module": "user",
+ "function": "login",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "SiteAccess",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "2282622326"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1766001124"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/351",
+ "id": 351,
+ "module": "content",
+ "function": "view_embed",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "Class",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "5"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "12"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/352",
+ "id": 352,
+ "module": "user",
+ "function": "register"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/353",
+ "id": 353,
+ "module": "user",
+ "function": "password"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.xml.example b/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.xml.example
new file mode 100644
index 000000000..6f546c316
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/policies/GET/PolicyList.xml.example
@@ -0,0 +1,53 @@
+
+
+
+ 349
+ content
+ read
+
+
+
+
+
+
+
+
+
+
+
+ 350
+ user
+ login
+
+
+
+
+
+
+
+
+
+
+ 351
+ content
+ view_embed
+
+
+
+
+
+
+
+
+
+
+ 352
+ user
+ register
+
+
+ 353
+ user
+ password
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.json.example b/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.json.example
new file mode 100644
index 000000000..6cdbc21f2
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.json.example
@@ -0,0 +1,71 @@
+{
+ "RoleList": {
+ "_media-type": "application/vnd.ibexa.api.RoleList+json",
+ "_href": "/api/ibexa/v2/user/roles",
+ "Role": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/1",
+ "identifier": "Anonymous",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2",
+ "identifier": "Administrator",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/2/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/3",
+ "identifier": "Editor",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/3/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/4",
+ "identifier": "Member",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/4/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/10",
+ "identifier": "NewRole",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/10/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/14",
+ "identifier": "NewRole5",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/14/policies"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/15",
+ "identifier": "NewRole7",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/15/policies"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.xml.example
new file mode 100644
index 000000000..a408cb426
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/GET/RoleList.xml.example
@@ -0,0 +1,31 @@
+
+
+
+ Anonymous
+
+
+
+ Administrator
+
+
+
+ Editor
+
+
+
+ Member
+
+
+
+ NewRole
+
+
+
+ NewRole5
+
+
+
+ NewRole7
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.json.example b/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.json.example
new file mode 100644
index 000000000..f26242811
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/21",
+ "identifier": "NewRole",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/21/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.xml.example
new file mode 100644
index 000000000..0d7808c86
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/POST/Role.xml.example
@@ -0,0 +1,5 @@
+
+
+ NewRole
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example b/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example
new file mode 100644
index 000000000..c2cfef57e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example
@@ -0,0 +1,5 @@
+{
+ "RoleInput": {
+ "identifier": "NewRole"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example
new file mode 100644
index 000000000..febdc5635
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example
@@ -0,0 +1,4 @@
+
+
+ NewRole
+
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.json.example
new file mode 100644
index 000000000..f26242811
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/21",
+ "identifier": "NewRole",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/21/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.xml.example
new file mode 100644
index 000000000..7909c201a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/GET/Role.xml.example
@@ -0,0 +1,5 @@
+
+
+ NewRole
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.json.example
new file mode 100644
index 000000000..e7295d979
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/21",
+ "identifier": "NewIdentifier",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/21/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.xml.example
new file mode 100644
index 000000000..bf7ef5438
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/Role.xml.example
@@ -0,0 +1,5 @@
+
+
+ NewIdentifier
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.json.example
new file mode 100644
index 000000000..d31874469
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.json.example
@@ -0,0 +1,5 @@
+{
+ "RoleInput": {
+ "identifier": "NewIdentifier"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.xml.example
new file mode 100644
index 000000000..ffe9e53bb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/PATCH/RoleInput.xml.example
@@ -0,0 +1,4 @@
+
+
+ NewIdentifier
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.json.example
new file mode 100644
index 000000000..8bdccb5a3
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/6",
+ "identifier": "Editor",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/6/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.xml.example
new file mode 100644
index 000000000..ba485b805
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.xml.example
@@ -0,0 +1,5 @@
+
+
+ MyRole
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.json.example
new file mode 100644
index 000000000..9d3c937ee
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/27",
+ "identifier": "Anonymous",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/27/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.xml.example
new file mode 100644
index 000000000..79aa775ec
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/GET/Role.xml.example
@@ -0,0 +1,5 @@
+
+
+ Anonymous
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example
new file mode 100644
index 000000000..cfd1b3d0c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example
@@ -0,0 +1,11 @@
+{
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/6",
+ "identifier": "UpdatedIdentifier",
+ "Policies": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/6/policies"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example
new file mode 100644
index 000000000..66e1a057a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example
@@ -0,0 +1,5 @@
+
+
+ UpdatedIdentifier
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.json.example
new file mode 100644
index 000000000..23bed0ebf
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.json.example
@@ -0,0 +1,5 @@
+{
+ "RoleInput": {
+ "identifier": "UpdatedIdentifier"
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.xml.example
new file mode 100644
index 000000000..1796642ea
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/RoleInput.xml.example
@@ -0,0 +1,4 @@
+
+
+ UpdatedIdentifier
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.json.example
new file mode 100644
index 000000000..9b48841e3
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.json.example
@@ -0,0 +1,104 @@
+{
+ "PolicyList": {
+ "_media-type": "application/vnd.ibexa.api.PolicyList+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies",
+ "Policy": [
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/349",
+ "id": 349,
+ "module": "content",
+ "function": "read",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "3"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "6"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/350",
+ "id": 350,
+ "module": "user",
+ "function": "login",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "SiteAccess",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "2282622326"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1766001124"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/351",
+ "id": 351,
+ "module": "content",
+ "function": "view_embed",
+ "limitations": {
+ "limitation": [
+ {
+ "_identifier": "Class",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "5"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "12"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/352",
+ "id": 352,
+ "module": "user",
+ "function": "register"
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/353",
+ "id": 353,
+ "module": "user",
+ "function": "password"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.xml.example
new file mode 100644
index 000000000..8a8b328e5
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.xml.example
@@ -0,0 +1,53 @@
+
+
+
+ 349
+ content
+ read
+
+
+
+
+
+
+
+
+
+
+
+ 350
+ user
+ login
+
+
+
+
+
+
+
+
+
+
+ 351
+ content
+ view_embed
+
+
+
+
+
+
+
+
+
+
+ 352
+ user
+ register
+
+
+ 353
+ user
+ password
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/Policy.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/Policy.xml.example
new file mode 100644
index 000000000..d3db9de1a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/Policy.xml.example
@@ -0,0 +1,17 @@
+
+ 55
+ content
+ create
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/PolicyCreate.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/PolicyCreate.xml.example
new file mode 100644
index 000000000..1bb010014
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/POST/PolicyCreate.xml.example
@@ -0,0 +1,17 @@
+
+
+ content
+ create
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example
new file mode 100644
index 000000000..dd22b0a2d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example
@@ -0,0 +1,9 @@
+{
+ "Policy": {
+ "_media-type": "application/vnd.ibexa.api.Policy+json",
+ "_href": "/api/ibexa/v2/user/roles/1/policies/352",
+ "id": 352,
+ "module": "user",
+ "function": "register"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.xml.example
new file mode 100644
index 000000000..8240b8750
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.xml.example
@@ -0,0 +1,19 @@
+
+ 45
+ content
+ create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example
new file mode 100644
index 000000000..86cfd7746
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example
@@ -0,0 +1,17 @@
+
+ 55
+ content
+ create
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/PolicyUpdate.xml.example b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/PolicyUpdate.xml.example
new file mode 100644
index 000000000..47ff30ff3
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/PolicyUpdate.xml.example
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.json.example b/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.json.example
new file mode 100644
index 000000000..879723680
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.json.example
@@ -0,0 +1,12 @@
+{
+ "Session": {
+ "_media-type": "application/vnd.ibexa.api.Session",
+ "name": "eZSSID",
+ "identifier": "go327ij2cirpo59pb6rrv2a4el2",
+ "csrfToken": "23lkneri34ijajedfw39orj3j93",
+ "User": {
+ "_href": "/user/users/14",
+ "_media-type": "application/vnd.ibexa.api.User+json"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example b/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example
new file mode 100644
index 000000000..ad2418606
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example
@@ -0,0 +1,7 @@
+
+
+ eZSSID
+ go327ij2cirpo59pb6rrv2a4el2
+ 23lkneri34ijajedfw39orj3j93
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.json.example b/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.json.example
new file mode 100644
index 000000000..9b45a75ce
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.json.example
@@ -0,0 +1,7 @@
+{
+ "SessionInput": {
+ "_media-type": "application/vnd.ibexa.api.SessionInput",
+ "login": "admin",
+ "password": "secret"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.xml.example b/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.xml.example
new file mode 100644
index 000000000..ae0f88db0
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.xml.example
@@ -0,0 +1,5 @@
+
+
+ admin
+ secret
+
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example b/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example
new file mode 100644
index 000000000..879723680
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example
@@ -0,0 +1,12 @@
+{
+ "Session": {
+ "_media-type": "application/vnd.ibexa.api.Session",
+ "name": "eZSSID",
+ "identifier": "go327ij2cirpo59pb6rrv2a4el2",
+ "csrfToken": "23lkneri34ijajedfw39orj3j93",
+ "User": {
+ "_href": "/user/users/14",
+ "_media-type": "application/vnd.ibexa.api.User+json"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.xml.example b/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.xml.example
new file mode 100644
index 000000000..039aa875c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.xml.example
@@ -0,0 +1,7 @@
+
+
+ eZSSID
+ go327ij2cirpo59pb6rrv2a4el2
+ 23lkneri34ijajedfw39orj3j93
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.json.example b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.json.example
new file mode 100644
index 000000000..3de11a92c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.json.example
@@ -0,0 +1,7 @@
+{
+ "JWT": {
+ "_media-type": "application/vnd.ibexa.api.JWT+json",
+ "_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDI4NDA3ODAsImV4cCI6MTYwMjg0NDM4MCwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoiYWRtaW4ifQ.0LHa799HwSwwfDBZd2V0q2xHwGt86PpyZamKnXHQyYI",
+ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDI4NDA3ODAsImV4cCI6MTYwMjg0NDM4MCwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoiYWRtaW4ifQ.0LHa799HwSwwfDBZd2V0q2xHwGt86PpyZamKnXHQyYI"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.xml.example b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.xml.example
new file mode 100644
index 000000000..7d59afac2
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.xml.example
@@ -0,0 +1,4 @@
+
+
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDI4NDA3NjEsImV4cCI6MTYwMjg0NDM2MSwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoiYWRtaW4ifQ.LsmdVjad7wMwVQUo4vSftT0zHbJyArOMd23b417E2jI
+
diff --git a/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.json.example b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.json.example
new file mode 100644
index 000000000..cc2dc54d6
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.json.example
@@ -0,0 +1,7 @@
+{
+ "JWTInput": {
+ "_media-type": "application/vnd.ibexa.api.JWTInput",
+ "username": "admin",
+ "password": "publish"
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.xml.example b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.xml.example
new file mode 100644
index 000000000..b7a053478
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.xml.example
@@ -0,0 +1,4 @@
+
+ publish
+ admin
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.json.example b/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.json.example
new file mode 100644
index 000000000..bd915b1cc
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.json.example
@@ -0,0 +1,155 @@
+{
+ "UserList": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/users",
+ "User": [
+ {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14",
+ "_id": 14,
+ "_remoteId": "1bb4fe25487f05527efa8bfd394cecc7",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4"
+ },
+ "name": "Administrator User",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/13/15"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/locations"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/14/groups"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "publishDate": "2002-10-06T16:13:50+00:00",
+ "lastModificationDate": "2011-03-25T14:07:04+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions/3",
+ "VersionInfo": {
+ "id": 499,
+ "versionNo": 3,
+ "status": "PUBLISHED",
+ "modificationDate": "2011-03-25T14:07:04+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2011-03-25T14:03:03+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Administrator User"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/14"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 28,
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Administrator"
+ },
+ {
+ "id": 29,
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "User"
+ },
+ {
+ "id": 30,
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezuser",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 14,
+ "login": "admin",
+ "email": "admin@link.invalid",
+ "passwordUpdatedAt": null,
+ "enabled": true,
+ "maxLogin": 10,
+ "plainPassword": null
+ }
+ },
+ {
+ "id": 178,
+ "fieldDefinitionIdentifier": "signature",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "eztext",
+ "fieldValue": null
+ },
+ {
+ "id": 180,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezimage",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/14/versions/3/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "login": "admin",
+ "email": "admin@link.invalid",
+ "enabled": true,
+ "UserGroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/users/14/groups"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/14/roles"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.xml.example
new file mode 100644
index 000000000..6dbef3cdf
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/GET/UserList.xml.example
@@ -0,0 +1,88 @@
+
+
+
+
+ Administrator User
+
+
+
+
+
+
+ 2002-10-06T18:13:50+02:00
+ 2011-03-25T15:07:04+01:00
+ eng-GB
+ true
+
+
+ 499
+ 3
+ PUBLISHED
+ 2011-03-25T15:07:04+01:00
+
+ 2011-03-25T15:03:03+01:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Administrator User
+
+
+
+
+
+ 28
+ first_name
+ eng-GB
+ ezstring
+ Administrator
+
+
+ 29
+ last_name
+ eng-GB
+ ezstring
+ User
+
+
+ 30
+ user_account
+ eng-GB
+ ezuser
+
+ true
+ 14
+ admin
+ nospam@ibexa.co
+ true
+ 10
+
+
+
+ 178
+ signature
+ eng-GB
+ eztext
+
+
+
+ 180
+ image
+ eng-GB
+ ezimage
+
+
+
+
+
+ admin
+ nospam@ibexa.co
+ true
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/GET/UserRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/GET/UserRefList.xml.example
new file mode 100644
index 000000000..c8cf9a66d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/GET/UserRefList.xml.example
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example
new file mode 100644
index 000000000..e0318f6dd
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example
@@ -0,0 +1,155 @@
+{
+ "UserList": {
+ "_media-type": "application/vnd.ibexa.api.UserList+json",
+ "_href": "/api/ibexa/v2/user/users",
+ "User": [
+ {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/79",
+ "_id": 79,
+ "_remoteId": "bcf0764b417f05af21852a1f03fb1f13",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4"
+ },
+ "name": "Jose Vargas",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/12/79"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/locations"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/79/groups"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/10"
+ },
+ "publishDate": "2021-06-29T08:23:42+00:00",
+ "lastModificationDate": "2021-06-29T08:23:42+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions/1",
+ "VersionInfo": {
+ "id": 547,
+ "versionNo": 1,
+ "status": "PUBLISHED",
+ "modificationDate": "2021-06-29T08:23:42+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/10"
+ },
+ "creationDate": "2021-06-29T08:23:42+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Jose Vargas"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/79"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 342,
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Jose"
+ },
+ {
+ "id": 343,
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Vargas"
+ },
+ {
+ "id": 344,
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezuser",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 79,
+ "login": "josevargas",
+ "email": "aa@bb.cc",
+ "passwordUpdatedAt": 1624955022,
+ "enabled": true,
+ "maxLogin": 0,
+ "plainPassword": null
+ }
+ },
+ {
+ "id": 345,
+ "fieldDefinitionIdentifier": "signature",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "eztext",
+ "fieldValue": null
+ },
+ {
+ "id": 346,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezimage",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions/1/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "login": "josevargas",
+ "email": "aa@bb.cc",
+ "enabled": true,
+ "UserGroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/users/79/groups"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/79/roles"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example
new file mode 100644
index 000000000..fab328704
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example
@@ -0,0 +1,96 @@
+
+
+
+
+ Jose Vargas
+
+
+
+
+
+
+ 2021-06-29T08:23:42+00:00
+ 2021-06-29T08:23:42+00:00
+ eng-GB
+ true
+
+
+ 547
+ 1
+ PUBLISHED
+ 2021-06-29T08:23:42+00:00
+
+ 2021-06-29T08:23:42+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Jose Vargas
+
+
+
+
+
+ 342
+ first_name
+ eng-GB
+ ezstring
+ Jose
+
+
+ 343
+ last_name
+ eng-GB
+ ezstring
+ Vargas
+
+
+ 344
+ user_account
+ eng-GB
+ ezuser
+
+ true
+ 79
+ josevargas
+ aa@bb.cc
+ 1624955022
+ true
+ 0
+
+
+
+
+ 345
+ signature
+ eng-GB
+ eztext
+
+
+
+ 346
+ image
+ eng-GB
+ ezimage
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user
+
+
+ image/svg+xml
+
+
+ josevargas
+ aa@bb.cc
+ true
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.json.example
new file mode 100644
index 000000000..8f1a529db
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.json.example
@@ -0,0 +1,149 @@
+{
+ "User": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/79",
+ "_id": 79,
+ "_remoteId": "bcf0764b417f05af21852a1f03fb1f13",
+ "ContentType": {
+ "_media-type": "application/vnd.ibexa.api.ContentType+json",
+ "_href": "/api/ibexa/v2/content/types/4"
+ },
+ "name": "Jose Vargas",
+ "Versions": {
+ "_media-type": "application/vnd.ibexa.api.VersionList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions"
+ },
+ "Section": {
+ "_media-type": "application/vnd.ibexa.api.Section+json",
+ "_href": "/api/ibexa/v2/content/sections/2"
+ },
+ "MainLocation": {
+ "_media-type": "application/vnd.ibexa.api.Location+json",
+ "_href": "/api/ibexa/v2/content/locations/1/5/12/79"
+ },
+ "Locations": {
+ "_media-type": "application/vnd.ibexa.api.LocationList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/locations"
+ },
+ "Groups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/79/groups"
+ },
+ "Owner": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/10"
+ },
+ "publishDate": "2021-06-29T08:23:42+00:00",
+ "lastModificationDate": "2021-07-29T12:00:24+00:00",
+ "mainLanguageCode": "eng-GB",
+ "alwaysAvailable": true,
+ "Version": {
+ "_media-type": "application/vnd.ibexa.api.Version+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions/11",
+ "VersionInfo": {
+ "id": 614,
+ "versionNo": 11,
+ "status": "PUBLISHED",
+ "modificationDate": "2021-07-29T12:00:24+00:00",
+ "Creator": {
+ "_media-type": "application/vnd.ibexa.api.User+json",
+ "_href": "/api/ibexa/v2/user/users/14"
+ },
+ "creationDate": "2021-07-29T12:00:24+00:00",
+ "initialLanguageCode": "eng-GB",
+ "languageCodes": "eng-GB",
+ "VersionTranslationInfo": {
+ "_media-type": "application/vnd.ibexa.api.VersionTranslationInfo+json",
+ "Language": [
+ {
+ "languageCode": "eng-GB"
+ }
+ ]
+ },
+ "names": {
+ "value": [
+ {
+ "_languageCode": "eng-GB",
+ "#text": "Jose Vargas"
+ }
+ ]
+ },
+ "Content": {
+ "_media-type": "application/vnd.ibexa.api.ContentInfo+json",
+ "_href": "/api/ibexa/v2/content/objects/79"
+ }
+ },
+ "Fields": {
+ "field": [
+ {
+ "id": 342,
+ "fieldDefinitionIdentifier": "first_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Jose"
+ },
+ {
+ "id": 343,
+ "fieldDefinitionIdentifier": "last_name",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezstring",
+ "fieldValue": "Vargas"
+ },
+ {
+ "id": 344,
+ "fieldDefinitionIdentifier": "user_account",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezuser",
+ "fieldValue": {
+ "hasStoredLogin": true,
+ "contentId": 79,
+ "login": "josevargas",
+ "email": "aa@bb.cc",
+ "passwordUpdatedAt": null,
+ "enabled": false,
+ "maxLogin": 0,
+ "plainPassword": null
+ }
+ },
+ {
+ "id": 345,
+ "fieldDefinitionIdentifier": "signature",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "eztext",
+ "fieldValue": null
+ },
+ {
+ "id": 346,
+ "fieldDefinitionIdentifier": "image",
+ "languageCode": "eng-GB",
+ "fieldTypeIdentifier": "ezimage",
+ "fieldValue": null
+ }
+ ]
+ },
+ "Relations": {
+ "_media-type": "application/vnd.ibexa.api.RelationList+json",
+ "_href": "/api/ibexa/v2/content/objects/79/versions/11/relations",
+ "Relation": []
+ },
+ "Thumbnail": {
+ "_media-type": "application/vnd.ibexa.api.Thumbnail+json",
+ "resource": "/bundles/ezplatformadminui/img/ez-icons.svg#user",
+ "width": null,
+ "height": null,
+ "mimeType": "image/svg+xml"
+ }
+ },
+ "login": "josevargas",
+ "email": "aa@bb.cc",
+ "enabled": false,
+ "UserGroups": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupList+json",
+ "_href": "/api/ibexa/v2/user/users/79/groups"
+ },
+ "Roles": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/79/roles"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.xml.example
new file mode 100644
index 000000000..caf3abbaf
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.xml.example
@@ -0,0 +1,94 @@
+
+
+
+ Jose Vargas
+
+
+
+
+
+
+ 2021-06-29T08:23:42+00:00
+ 2021-07-29T11:45:07+00:00
+ eng-GB
+ true
+
+
+ 609
+ 6
+ PUBLISHED
+ 2021-07-29T11:45:07+00:00
+
+ 2021-07-29T11:45:07+00:00
+ eng-GB
+ eng-GB
+
+
+ eng-GB
+
+
+
+ Jose Vargas
+
+
+
+
+
+ 342
+ first_name
+ eng-GB
+ ezstring
+ Jose
+
+
+ 343
+ last_name
+ eng-GB
+ ezstring
+ Vargas
+
+
+ 344
+ user_account
+ eng-GB
+ ezuser
+
+ true
+ 79
+ josevargas
+ aa@bb.cc
+
+ false
+ 0
+
+
+
+
+ 345
+ signature
+ eng-GB
+ eztext
+
+
+
+ 346
+ image
+ eng-GB
+ ezimage
+
+
+
+
+
+ /bundles/ezplatformadminui/img/ez-icons.svg#user
+
+
+ image/svg+xml
+
+
+ josevargas
+ aa@bb.cc
+ false
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.json.example
new file mode 100644
index 000000000..fd43e1d7f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.json.example
@@ -0,0 +1,6 @@
+{
+ "UserUpdate": {
+ "login": "josevargas",
+ "enabled": false
+ }
+}
\ No newline at end of file
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.xml.example
new file mode 100644
index 000000000..fe09ab444
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.xml.example
@@ -0,0 +1,5 @@
+
+
+ josevargas
+ false
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/GET/UserGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/GET/UserGroupRefList.xml.example
new file mode 100644
index 000000000..dc45cf331
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/GET/UserGroupRefList.xml.example
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.json.example
new file mode 100644
index 000000000..8e7c8f7cb
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.json.example
@@ -0,0 +1,24 @@
+{
+ "UserGroupRefList": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/115/groups",
+ "UserGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/12",
+ "unassign": {
+ "_href": "/api/ibexa/v2/user/users/115/groups/12",
+ "_method": "DELETE"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13",
+ "unassign": {
+ "_href": "/api/ibexa/v2/user/users/115/groups/13",
+ "_method": "DELETE"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example
new file mode 100644
index 000000000..ed2ceff01
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/DELETE/UserGroupRefList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/DELETE/UserGroupRefList.xml.example
new file mode 100644
index 000000000..f0e5f585e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/DELETE/UserGroupRefList.xml.example
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example
new file mode 100644
index 000000000..1d5808dc1
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example
@@ -0,0 +1,12 @@
+{
+ "UserGroupRefList": {
+ "_media-type": "application/vnd.ibexa.api.UserGroupRefList+json",
+ "_href": "/api/ibexa/v2/user/users/57/groups",
+ "UserGroup": [
+ {
+ "_media-type": "application/vnd.ibexa.api.UserGroup+json",
+ "_href": "/api/ibexa/v2/user/groups/1/5/13"
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.json.example
new file mode 100644
index 000000000..b265f016e
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.json.example
@@ -0,0 +1,27 @@
+{
+ "RoleAssignmentList": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/115/roles",
+ "RoleAssignment": [
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/115/roles/2",
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1"
+ }
+ ]
+ }
+ },
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..1fb30959a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/GET/RoleAssignmentList.xml.example
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.json.example
new file mode 100644
index 000000000..ea756134d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.json.example
@@ -0,0 +1,23 @@
+{
+ "RoleAssignInput": {
+ "Role": {
+ "_href": "/api/ibexa/v2/user/roles/2",
+ "_media-type": "application/vnd.ibexa.api.RoleAssignInput+xml"
+ },
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_href": "/api/ibexa/v2/content/sections/1",
+ "_media-type": "application/vnd.ibexa.api.Section+xml"
+ },
+ {
+ "_href": "/api/ibexa/v2/content/sections/2",
+ "_media-type": "application/vnd.ibexa.api.Section+xml"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.xml.example
new file mode 100644
index 000000000..243f3ff7d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.xml.example
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.json.example
new file mode 100644
index 000000000..22b919336
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.json.example
@@ -0,0 +1,46 @@
+{
+ "RoleAssignmentList": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/115/roles",
+ "RoleAssignment": [
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/115/roles/2",
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "2"
+ }
+ ]
+ }
+ },
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/115/roles/2",
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "1"
+ }
+ ]
+ }
+ },
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..4800db41d
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example
new file mode 100644
index 000000000..16dc02334
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example
@@ -0,0 +1,24 @@
+{
+ "RoleAssignmentList": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignmentList+json",
+ "_href": "/api/ibexa/v2/user/users/57/roles",
+ "RoleAssignment": [
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/57/roles/1",
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/1"
+ }
+ },
+ {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/57/roles/2",
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/2"
+ }
+ }
+ ]
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.xml.example
new file mode 100644
index 000000000..2c74de453
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.xml.example
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.json.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.json.example
new file mode 100644
index 000000000..527244157
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.json.example
@@ -0,0 +1,21 @@
+{
+ "RoleAssignment": {
+ "_media-type": "application/vnd.ibexa.api.RoleAssignment+json",
+ "_href": "/api/ibexa/v2/user/users/113/roles/3",
+ "limitation": {
+ "_identifier": "Section",
+ "values": {
+ "ref": [
+ {
+ "_media-type": "application/vnd.ibexa.api.ref+json",
+ "_href": "6"
+ }
+ ]
+ }
+ },
+ "Role": {
+ "_media-type": "application/vnd.ibexa.api.Role+json",
+ "_href": "/api/ibexa/v2/user/roles/3"
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example
new file mode 100644
index 000000000..0511e11c5
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/views/POST/View.xml.v11.example b/src/bundle/Resources/api_platform/examples/views/POST/View.xml.v11.example
new file mode 100644
index 000000000..d476a11c8
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/views/POST/View.xml.v11.example
@@ -0,0 +1,67 @@
+
+
+ TitleView
+
+ false
+
+
+ 2
+
+ 10
+ 0
+
+ ascending
+
+
+
+
+
+
+
+
+
+
+
+ 2
+ 0
+ false
+ false
+
+ /1/2/
+ 1
+ 8
+ f3e90596361e31d496d4026eb624c983
+
+
+ PRIORITY
+ ASC
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+ 9
+
+
+
+ 1
+
+
+
+ 8
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.json.example b/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.json.example
new file mode 100644
index 000000000..eb4514cc9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.json.example
@@ -0,0 +1,28 @@
+{
+ "ViewInput": {
+ "identifier": "TitleView",
+ "Query": {
+ "Filter": {
+ "ContentTypeIdentifierCriterion": "image",
+ "SectionIdentifierCriterion": "media",
+ "DateMetadataCriterion": {
+ "Target": "modified",
+ "Value": 1675681020,
+ "Operator": "gte"
+ }
+ },
+ "limit": 10,
+ "offset": 0,
+ "SortClauses": {
+ "ContentName": "ascending"
+ },
+ "Aggregations": [
+ {
+ "ContentTypeTermAggregation": {
+ "name": "some name"
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.xml.example b/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.xml.example
new file mode 100644
index 000000000..45cc1f489
--- /dev/null
+++ b/src/bundle/Resources/api_platform/examples/views/POST/ViewInput.xml.example
@@ -0,0 +1,27 @@
+
+
+ TitleView
+
+
+ image
+ media
+
+ modified
+ 1675681020
+ gte
+
+
+ 10
+ 0
+
+ ascending
+
+
+
+
+ some name
+
+
+
+
+
diff --git a/src/bundle/Resources/api_platform/base_schemas.yml b/src/bundle/Resources/api_platform/schemas/base_schemas.yml
similarity index 100%
rename from src/bundle/Resources/api_platform/base_schemas.yml
rename to src/bundle/Resources/api_platform/schemas/base_schemas.yml
diff --git a/src/bundle/Resources/api_platform/schemas/bookmarks_schemas.yml b/src/bundle/Resources/api_platform/schemas/bookmarks_schemas.yml
new file mode 100644
index 000000000..d70804aed
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/bookmarks_schemas.yml
@@ -0,0 +1,80 @@
+schemas:
+ BookmarkList:
+ description: List of bookmarked Locations.
+ type: object
+ required:
+ - count
+ - items
+ properties:
+ count:
+ description: The total number of bookmarks.
+ type: integer
+ items:
+ description: List of bookmarked Locations.
+ type: array
+ items:
+ type: object
+ required:
+ - Location
+ - _media-type
+ - __href
+ properties:
+ Location:
+ type:
+ $ref: "#/components/schemas/Location"
+ _media-type:
+ type: string
+ __href:
+ type: string
+ BookmarkListWrapper:
+ type: object
+ required:
+ - BookmarkList
+ properties:
+ BookmarkList:
+ type:
+ $ref: "#/components/schemas/BookmarkList"
+ SummaryEntry:
+ type: object
+ required:
+ - identifier
+ - id
+ - names
+ - quantity
+ - Price
+ - PriceInclVat
+ - SubtotalPrice
+ - SubtotalPriceInclVat
+ - VatCategory
+ - Product
+ properties:
+ identifier:
+ type: string
+ id:
+ type: integer
+ names:
+ type:
+ $ref: "#/components/schemas/SummaryEntryNames"
+ quantity:
+ type: integer
+ Price:
+ type:
+ $ref: "#/components/schemas/RestPriceWrapper"
+ PriceInclVat:
+ type:
+ $ref: "#/components/schemas/RestPriceWrapper"
+ SubtotalPrice:
+ type:
+ $ref: "#/components/schemas/RestPriceWrapper"
+ SubtotalPriceInclVat:
+ type:
+ $ref: "#/components/schemas/RestPriceWrapper"
+ VatCategory:
+ type:
+ $ref: "#/components/schemas/VatCategory"
+ Product:
+ type:
+ $ref: "#/components/schemas/Product"
+ SummaryEntryNames:
+ type:
+ $ref: "#/components/schemas/ValueObject"
diff --git a/src/bundle/Resources/api_platform/schemas/content_locations_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_locations_schemas.yml
new file mode 100644
index 000000000..813f4f613
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_locations_schemas.yml
@@ -0,0 +1,189 @@
+schemas:
+ Location:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a Location in the Repository.
+ type: object
+ required:
+ - id
+ - priority
+ - hidden
+ - invisible
+ - remoteId
+ - ContentInfo
+ - ParentLocation
+ - pathString
+ - depth
+ - childCount
+ - sortField
+ - sortOrder
+ - Content
+ properties:
+ id:
+ description: The ID of the Location.
+ type: integer
+ priority:
+ description: Location priority. Position of the Location among its siblings when sorted using priority sort order.
+ type: integer
+ hidden:
+ description: Indicates that the Location entity has been explicitly marked as hidden.
+ type: boolean
+ invisible:
+ description: Indicates that the Location is implicitly marked as hidden by a parent Location.
+ type: boolean
+ remoteId:
+ description: Remote ID, universally unique identifier.
+ type: string
+ ContentInfo:
+ description: This class provides all version independent information of the content item.
+ type:
+ $ref: "#/components/schemas/ContentInfo"
+ ParentLocation:
+ description: Parent Location.
+ Children:
+ description: Children Location.
+ pathString:
+ description: The materialized path of the Location entry e.g. /1/2/.
+ type: string
+ depth:
+ description: Depth Location has in the Location tree.
+ type: integer
+ childCount:
+ description: Depth Location has in the Location tree.
+ type: integer
+ sortField:
+ description: "Specifies which property the child Locations should be sorted on. Map for Location sort fields to their respective SortClauses - class name/identifier and modified subnode. One of the fallowing values: PATH."
+ enum:
+ - PATH
+ - PUBLISHED
+ - MODIFIED
+ - SECTION
+ - DEPTH
+ - CLASS_IDENTIFIER
+ - CLASS_NAME
+ - PRIORITY
+ - NAME
+ - MODIFIED_SUBNODE
+ - NODE_ID
+ - CONTENTOBJECT_ID
+ type: string
+ sortOrder:
+ description: "Specifies whether the sort order should be ascending or descending. Map for Location sort order to their respective Query SORT constants. One of the fallowing values: const SORT_ORDER_DESC = 0; const SORT_ORDER_ASC = 1."
+ enum:
+ - ASC
+ - DESC
+ type: string
+ Content:
+ description: Represents a content item in a specific version.
+ UrlAliases:
+ description: This class represents URL aliases.
+ LocationWrapper:
+ type: object
+ required:
+ - Location
+ properties:
+ Location:
+ $ref: "#/components/schemas/Location"
+ LocationCreate:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - type: object
+ required:
+ - ParentLocation
+ - priority
+ - hidden
+ - sortField
+ - sortOrder
+ properties:
+ ParentLocation:
+ type: object
+ required:
+ - _href
+ properties:
+ _href:
+ xml:
+ attribute: true
+ name: href
+ type: string
+ priority:
+ type: string
+ hidden:
+ type: [string, boolean]
+ sortField:
+ type: string
+ sortOrder:
+ type: string
+ LocationCreateWrapper:
+ type: object
+ required:
+ - LocationCreate
+ properties:
+ LocationCreate:
+ $ref: "#/components/schemas/LocationCreate"
+ LocationUpdateStruct:
+ description: This class is used for updating Location meta data.
+ type: object
+ required:
+ - priority
+ - remoteId
+ - hidden
+ - sortField
+ - sortOrder
+ properties:
+ priority:
+ description: If set the Location priority is changed to the new value.
+ type: string
+ remoteId:
+ description: If set the Location gets a new remoteId. Needs to be a unique Location->remoteId string value.
+ type: string
+ hidden:
+ type: boolean
+ sortField:
+ description: If set the sortField is changed. The sort field specifies which property the child Locations should be sorted on. Valid values are found at {@link Location::SORT_FIELD_*}.
+ enum:
+ - PATH
+ - PUBLISHED
+ - MODIFIED
+ - SECTION
+ - DEPTH
+ - CLASS_IDENTIFIER
+ - CLASS_NAME
+ - PRIORITY
+ - NAME
+ - MODIFIED_SUBNODE
+ - NODE_ID
+ - CONTENTOBJECT_ID
+ type: string
+ sortOrder:
+ description: If set the sortOrder is changed. The sort order specifies whether the sort order should be ascending or descending. Valid values are {@link Location::SORT_ORDER_*}.
+ enum:
+ - ASC
+ - DESC
+ type: string
+ LocationUpdateStructWrapper:
+ type: object
+ required:
+ - LocationUpdate
+ properties:
+ LocationUpdate:
+ $ref: "#/components/schemas/LocationUpdateStruct"
+ LocationList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a queried Location list holding a totalCount and a partial list of Locations (by offset/limit parameters and permission filters).
+ type: object
+ required:
+ - Location
+ properties:
+ Location:
+ description: The partial list of Locations controlled by offset/limit.
+ type: array
+ items:
+ $ref: "#/components/schemas/Ref"
+ LocationListWrapper:
+ type: object
+ required:
+ - LocationList
+ properties:
+ LocationList:
+ $ref: "#/components/schemas/LocationList"
diff --git a/src/bundle/Resources/api_platform/schemas/content_objects_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_objects_schemas.yml
new file mode 100644
index 000000000..c83f50a66
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_objects_schemas.yml
@@ -0,0 +1,506 @@
+schemas:
+ Content:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Content ID matcher class.
+ type: object
+ required:
+ - _remoteId
+ - _id
+ - ContentType
+ - Name
+ - Versions
+ - CurrentVersion
+ - Section
+ - Locations
+ - Owner
+ - mainLanguageCode
+ - currentVersionNo
+ - alwaysAvailable
+ - status
+ - ObjectStates
+ properties:
+ _remoteId:
+ description: Remote ID of the content type.
+ xml:
+ attribute: true
+ name: remoteId
+ type: string
+ _id:
+ description: Unique ID of the content type.
+ xml:
+ attribute: true
+ name: id
+ type: integer
+ ContentType:
+ description: Content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Name:
+ description: Name of the domain object in a given language.
+ type: string
+ Versions:
+ description: Returns the VersionInfo for this version.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ CurrentVersion:
+ description: Current version.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Section:
+ description: The Section to which the content item is assigned to.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Locations:
+ description: Location of the content item.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Owner:
+ description: The owner of the content item.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ lastModificationDate:
+ description: Content item modification date.
+ type: string
+ format: date-time
+ publishedDate:
+ description: Content item publication date.
+ type: string
+ format: date-time
+ mainLanguageCode:
+ description: The main language code of the content item.
+ type: string
+ currentVersionNo:
+ description: Current version number is the version number of the published version or the version number of a newly created draft (which is 1).
+ type: integer
+ alwaysAvailable:
+ description: Indicates if the content item is shown in the main language if it's not present in an other requested language.
+ type: boolean
+ status:
+ description: "Status of the content. Possible values: const STATUS_DRAFT = 0;const STATUS_PUBLISHED = 1; const STATUS_TRASHED = 2."
+ type: string
+ ObjectStates:
+ description: Object states.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ ContentWrapper:
+ type: object
+ required:
+ - Content
+ properties:
+ Content:
+ $ref: "#/components/schemas/Content"
+ ContentCreate:
+ description: This class is used for creating a new content item.
+ type: object
+ required:
+ - ContentType
+ - mainLanguageCode
+ - LocationCreate
+ - fields
+ properties:
+ ContentType:
+ description: The content type for which the new content item is created.
+ type:
+ oneOf:
+ - "#/components/schemas/Content"
+ - "#/components/schemas/Href"
+ Section:
+ description: The Section the content item is assigned to. If not set the Section of the parent is used or a default Section.
+ type:
+ $ref: "#/components/schemas/Href"
+ User:
+ description: The owner of the content. If not given the current authenticated User is set as owner.
+ type: integer
+ alwaysAvailable:
+ description: Indicates if the content item is shown in the main language if it's not present in an other requested language.
+ type: string
+ remoteId:
+ description: Remote identifier used as a custom identifier for the content item. Needs to be a unique Content->remoteId string value.
+ type: string
+ mainLanguageCode:
+ description: The main language code for the content. This language will also be used for as initial language for the first created version. It is also used as default language for added fields.
+ type: string
+ modificationDate:
+ description: Modification date. If not given, the current integer is used.
+ type: string
+ format: date-time
+ LocationCreate:
+ type: object
+ fields:
+ type: object
+ required:
+ - field
+ properties:
+ field:
+ type: array
+ items:
+ type: object
+ ContentCreateWrapper:
+ type: object
+ required:
+ - ContentCreate
+ properties:
+ ContentCreate:
+ $ref: "#/components/schemas/ContentCreate"
+ ContentUpdate:
+ description: This class is used to update a Content.
+ type: object
+ required:
+ - mainLanguageCode
+ - Section
+ - MainLocation
+ - Owner
+ - alwaysAvailable
+ - remoteId
+ properties:
+ mainLanguageCode:
+ type: string
+ Section:
+ type:
+ $ref: "#/components/schemas/Section"
+ MainLocation:
+ type:
+ $ref: "#/components/schemas/Location"
+ Owner:
+ type:
+ $ref: "#/components/schemas/User"
+ alwaysAvailable:
+ type: boolean
+ remoteId:
+ type: string
+ ContentInfo:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class provides all version independent information of the content item.
+ type: object
+ required:
+ - Content
+ properties:
+ Content:
+ description: Content ID matcher class.
+ type:
+ $ref: "#/components/schemas/Content"
+ ContentInfoWrapper:
+ type: object
+ required:
+ - ContentInfo
+ properties:
+ ContentInfo:
+ $ref: "#/components/schemas/ContentInfo"
+ ContentMetadataUpdate:
+ description: This class is used to update a Content metadata.
+ type: object
+ required:
+ - ownerId
+ - publishedDate
+ - modificationDate
+ - mainLanguageCode
+ - alwaysAvailable
+ - remoteId
+ - mainLocationId
+ - name
+ properties:
+ ownerId: {}
+ publishedDate:
+ type: string
+ format: date-time
+ modificationDate:
+ type: string
+ format: date-time
+ mainLanguageCode:
+ type: string
+ alwaysAvailable:
+ type: boolean
+ remoteId:
+ type: string
+ mainLocationId: {}
+ name:
+ type: string
+ ContentCreateContentType:
+ type: object
+ required:
+ - _href
+ - FieldDefinitions
+ properties:
+ _href:
+ xml:
+ attribute: true
+ name: href
+ type: string
+ FieldDefinitions:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - type: object
+ properties:
+ FieldDefinitions:
+ type: array
+ items:
+ $ref: "#/components/schemas/FieldDefinition"
+ ContentObjectStates:
+ description: Represents a list of object states.
+ type: object
+ required:
+ - ObjectState
+ properties:
+ ObjectState:
+ description: List of object state values.
+ type: array
+ items:
+ $ref: "#/components/schemas/Href"
+ ContentObjectStatesWrapper:
+ type: object
+ required:
+ - ContentObjectStates
+ properties:
+ ContentObjectStates:
+ $ref: "#/components/schemas/ContentObjectStates"
+ VersionInfo:
+ description: This class holds version information data. It also contains the corresponding {@link Content} to which the version belongs to.
+ type: object
+ required:
+ - id
+ - versionNo
+ - status
+ - modificationDate
+ - Creator
+ - creationDate
+ - initialLanguageCode
+ - languageCodes
+ - VersionTranslationInfo
+ - names
+ - Content
+ properties:
+ id:
+ description: Version ID.
+ type: integer
+ versionNo:
+ description: Version number. In contrast to {@link $id}, this is the version number, which only increments in scope of a single content item.
+ type: integer
+ status:
+ description: "One of: VersionInfo::STATUS_DRAFT=0, VersionInfo::STATUS_PUBLISHED=1, VersionInfo::STATUS_ARCHIVED=3."
+ enum:
+ - DRAFT
+ - PUBLISHED
+ - ARCHIVED
+ type: string
+ modificationDate:
+ description: The last modified date of this version.
+ type: string
+ format: date-time
+ Creator:
+ description: Creator of the version, in the search API this is referred to as the modifier of the published content.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ creationDate:
+ description: Content creation date.
+ type: string
+ format: date-time
+ initialLanguageCode:
+ description: The language code which is used for labeling a translation.
+ type: string
+ languageCodes:
+ description: List of languages in this version. Reflects which languages fields exists in for this version.
+ type: string
+ VersionTranslationInfo:
+ description: Translation information.
+ names:
+ description: Names.
+ type:
+ $ref: "#/components/schemas/ValueArray"
+ Content:
+ description: Represents a content item in a specific version.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Version:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Returns the VersionInfo for this version.
+ type: object
+ required:
+ - VersionInfo
+ - Fields
+ - Relations
+ properties:
+ VersionInfo:
+ description: VersionInfo for this version.
+ Fields:
+ type: object
+ required:
+ - field
+ properties:
+ field:
+ description: Fields of a Company content item.
+ type: array
+ items:
+ $ref: "#/components/schemas/Field"
+ Relations:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Relations of the user.
+ type: object
+ required:
+ - Relation
+ properties:
+ Relation:
+ type: array
+ items:
+ $ref: "#/components/schemas/Relation"
+ VersionWrapper:
+ type: object
+ required:
+ - Version
+ properties:
+ Version:
+ $ref: "#/components/schemas/Version"
+ VersionUpdate:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is used to update a content version.
+ type: object
+ required:
+ - modificationDate
+ - initialLanguageCode
+ - fields
+ properties:
+ modificationDate:
+ type: string
+ format: date-time
+ initialLanguageCode:
+ type: string
+ fields:
+ type: array
+ items:
+ $ref: "#/components/schemas/Field"
+ VersionUpdateWrapper:
+ type: object
+ required:
+ - VersionUpdate
+ properties:
+ VersionUpdate:
+ $ref: "#/components/schemas/VersionUpdate"
+ VersionList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of all versions of the content.
+ type: object
+ required:
+ - VersionItem
+ properties:
+ VersionItem:
+ type: array
+ items:
+ $ref: "#/components/schemas/VersionItem"
+ VersionListWrapper:
+ type: object
+ required:
+ - VersionList
+ properties:
+ VersionList:
+ $ref: "#/components/schemas/VersionList"
+ VersionItem:
+ description: Version of content.
+ type: object
+ required:
+ - Version
+ - VersionInfo
+ properties:
+ Version:
+ description: Returns the VersionInfo for this version.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ VersionInfo:
+ type:
+ $ref: "#/components/schemas/VersionInfo"
+ VersionTranslationInfo:
+ description: Translation information.
+ type: object
+ required:
+ - _media-type
+ - Language
+ properties:
+ _media-type:
+ type: string
+ Language:
+ type: array
+ items:
+ $ref: "#/components/schemas/LanguageCode"
+ LanguageCode:
+ description: Language code.
+ type: object
+ required:
+ - languageCode
+ properties:
+ languageCode:
+ type: string
+ Relation:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Class representing a relation between content.
+ type: object
+ required:
+ - SourceContent
+ - DestinationContent
+ - RelationType
+ properties:
+ SourceContent:
+ description: The content of the source content of the relation.
+ type:
+ $ref: "#/components/schemas/Ref"
+ DestinationContent:
+ description: The content of the destination content of the relation.
+ type:
+ $ref: "#/components/schemas/Ref"
+ RelationType:
+ description: "The relation type bitmask. Relations: Relation::COMMON = 1, Relation::EMBED = 2, Relation::LINK = 4, Relation::FIELD = 8, Relation::ASSET = 16"
+ type: string
+ RelationWrapper:
+ type: object
+ required:
+ - Relation
+ properties:
+ Relation:
+ $ref: "#/components/schemas/Relation"
+ RelationCreate:
+ type: object
+ required:
+ - Destination
+ properties:
+ Destination:
+ type:
+ $ref: "#/components/schemas/Href"
+ RelationCreateWrapper:
+ type: object
+ required:
+ - RelationCreate
+ properties:
+ RelationCreate:
+ $ref: "#/components/schemas/RelationCreate"
+ RelationList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Class representing a list of relations between content.
+ type: object
+ required:
+ - Relation
+ properties:
+ Relation:
+ type: array
+ items:
+ $ref: "#/components/schemas/Relation"
+ RelationListWrapper:
+ type: object
+ required:
+ - Relations
+ properties:
+ Relations:
+ $ref: "#/components/schemas/RelationList"
+ Fields:
+ type: object
+ required:
+ - field
+ properties:
+ field:
+ type: array
+ items:
+ $ref: "#/components/schemas/Field"
diff --git a/src/bundle/Resources/api_platform/schemas/content_sections_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_sections_schemas.yml
new file mode 100644
index 000000000..2b8a5ccff
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_sections_schemas.yml
@@ -0,0 +1,63 @@
+schemas:
+ Section:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a Section.
+ type: object
+ required:
+ - sectionId
+ - identifier
+ - name
+ properties:
+ sectionId:
+ description: ID of the Section.
+ type: integer
+ identifier:
+ description: Unique identifier of the Section.
+ type: string
+ name:
+ description: Name of the Section.
+ type: string
+ SectionWrapper:
+ type: object
+ required:
+ - Section
+ properties:
+ Section:
+ $ref: "#/components/schemas/Section"
+ SectionInput:
+ type: object
+ required:
+ - identifier
+ - name
+ properties:
+ identifier:
+ type: string
+ name:
+ type: string
+ SectionInputWrapper:
+ type: object
+ required:
+ - SectionInput
+ properties:
+ SectionInput:
+ $ref: "#/components/schemas/SectionInput"
+ SectionList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a Section list.
+ type: object
+ required:
+ - Section
+ properties:
+ Section:
+ type: array
+ items:
+ $ref: "#/components/schemas/Section"
+ SectionListWrapper:
+ type: object
+ required:
+ - SectionList
+ properties:
+ SectionList:
+ $ref: "#/components/schemas/SectionList"
diff --git a/src/bundle/Resources/api_platform/schemas/content_trash_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_trash_schemas.yml
new file mode 100644
index 000000000..c5aec9ffa
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_trash_schemas.yml
@@ -0,0 +1,30 @@
+schemas:
+ Trash:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - type: object
+ required:
+ - TrashItem
+ properties:
+ TrashItem:
+ type: array
+ items:
+ $ref: "#/components/schemas/TrashItem"
+ TrashWrapper:
+ type: object
+ required:
+ - Trash
+ properties:
+ Trash:
+ $ref: "#/components/schemas/Trash"
+ TrashItem:
+ description: This class represents a trash item, which is actually a trashed Location.
+ type:
+ $ref: "#/components/schemas/Location"
+ TrashItemWrapper:
+ type: object
+ required:
+ - TrashItem
+ properties:
+ TrashItem:
+ $ref: "#/components/schemas/TrashItem"
diff --git a/src/bundle/Resources/api_platform/schemas/content_type_groups_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_type_groups_schemas.yml
new file mode 100644
index 000000000..d32dbba68
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_type_groups_schemas.yml
@@ -0,0 +1,104 @@
+schemas:
+ ContentTypeGroup:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a content type group value.
+ type: object
+ required:
+ - id
+ - identifier
+ - created
+ - modified
+ - Creator
+ - Modifier
+ - ContentTypes
+ properties:
+ id:
+ description: Primary key.
+ type: integer
+ identifier:
+ description: Readable string identifier of a group.
+ type: string
+ created:
+ description: Created date (integer).
+ type: string
+ format: date-time
+ modified:
+ description: Modified date (integer).
+ type: string
+ format: date-time
+ Creator:
+ description: Creator User ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Modifier:
+ description: Modifier User ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ ContentTypes:
+ description: Content types.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ ContentTypeGroupWrapper:
+ type: object
+ required:
+ - ContentTypeGroup
+ properties:
+ ContentTypeGroup:
+ $ref: "#/components/schemas/ContentTypeGroup"
+ ContentTypeGroupInput:
+ type: object
+ ContentTypeGroupInputWrapper:
+ type: object
+ required:
+ - ContentTypeGroupInput
+ properties:
+ ContentTypeGroupInput:
+ $ref: "#/components/schemas/ContentTypeGroupInput"
+ ContentTypeGroupListWrapper:
+ type: object
+ required:
+ - ContentTypeGroupList
+ properties:
+ ContentTypeGroupList:
+ $ref: "#/components/schemas/ContentTypeGroupList"
+ ContentTypeGroupRef:
+ description: Content type group reference.
+ type: array
+ items:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ type: object
+ properties:
+ unlink:
+ $ref: "#/components/schemas/Unlink"
+ ContentTypeGroupRefList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of content type groups references.
+ type: object
+ required:
+ - ContentTypeGroupRef
+ properties:
+ ContentTypeGroupRef:
+ type:
+ $ref: "#/components/schemas/ContentTypeGroupRef"
+ ContentTypeGroupList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of content type groups.
+ type: object
+ required:
+ - ContentTypeGroup
+ properties:
+ ContentTypeGroup:
+ type: array
+ items:
+ $ref: "#/components/schemas/ContentTypeGroup"
+ ContentTypeGroupRefListWrapper:
+ type: object
+ required:
+ - ContentTypeGroupRefList
+ properties:
+ ContentTypeGroupRefList:
+ $ref: "#/components/schemas/ContentTypeGroupRefList"
diff --git a/src/bundle/Resources/api_platform/schemas/content_types_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_types_schemas.yml
new file mode 100644
index 000000000..b86770294
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_types_schemas.yml
@@ -0,0 +1,561 @@
+schemas:
+ ContentType:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a content type.
+ type: object
+ required:
+ - id
+ - status
+ - identifier
+ - names
+ - descriptions
+ - creationDate
+ - modificationDate
+ - Creator
+ - Modifier
+ - Groups
+ - Draft
+ - remoteId
+ - urlAliasSchema
+ - nameSchema
+ - isContainer
+ - defaultAlwaysAvailable
+ - defaultSortField
+ - defaultSortOrder
+ - FieldDefinitions
+ properties:
+ id:
+ description: Content type ID.
+ type: integer
+ status:
+ description: "The status of the content type. Possible values: const STATUS_DEFINED = 0; Status constant for defined (aka published) Type, const STATUS_DRAFT = 1; Status constant for draft (aka temporary) Type; const STATUS_MODIFIED = 2; Status constant for modified (aka deferred for publishing) Type."
+ enum:
+ - DEFINED
+ - DRAFT
+ - MODIFIED
+ - PUBLISHED
+ type: string
+ identifier:
+ description: String identifier of a content type.
+ type: string
+ names:
+ description: Name of a content type.
+ descriptions:
+ description: Description of a content type.
+ creationDate:
+ description: Creation date of the content type.
+ type: string
+ format: date-time
+ modificationDate:
+ description: Modification date of the content type.
+ type: string
+ format: date-time
+ Creator:
+ description: Creator User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Modifier:
+ description: Modifier User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Groups:
+ description: Group User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Draft:
+ description: Draft of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ remoteId:
+ description: Unique remote ID of the content type.
+ type: string
+ urlAliasSchema:
+ description: URL alias schema. If nothing is provided, $nameSchema will be used instead.
+ type: [ string, 'null' ]
+ nameSchema:
+ description: Name schema. Can be composed of FieldDefinition identifier place holders.
+ type: string
+ isContainer:
+ description: A flag used to hint if content of this type may have children or not. It is highly recommended to respect this flag and not create/move content below non-containers. But this flag is not considered as part of the content model and the API will not in any way enforce this flag to be respected.
+ type: boolean
+ defaultAlwaysAvailable:
+ description: If an instance of a content type is created the always available flag is set by default to this value.
+ type: boolean
+ defaultSortField:
+ description: "Specifies which property the child Locations should be sorted on by default when created. Map for Location sort fields to their respective SortClauses - class name/identifier and modified subnode. One of the fallowing values: const SORT_FIELD_PATH = 1; const SORT_FIELD_PUBLISHED = 2; const SORT_FIELD_MODIFIED = 3; const SORT_FIELD_SECTION = 4; const SORT_FIELD_DEPTH = 5; const SORT_FIELD_PRIORITY = 8; const SORT_FIELD_NAME = 9; const SORT_FIELD_NODE_ID = 11; const SORT_FIELD_CONTENTOBJECT_ID = 12."
+ enum:
+ - PATH
+ - PUBLISHED
+ - MODIFIED
+ - SECTION
+ - DEPTH
+ - PRIORITY
+ - NAME
+ - NODE_ID
+ - CONTENTOBJECT_ID
+ type: string
+ defaultSortOrder:
+ description: "Specifies whether the sort order should be ascending or descending by default when created. Map for Location sort order to their respective Query SORT constants. Possible values: const SORT_ORDER_DESC = 0; const SORT_ORDER_ASC = 1."
+ enum:
+ - ASC
+ - DESC
+ type: string
+ FieldDefinitions:
+ description: This method returns the content type Field definitions from this type.
+ ContentTypeWrapper:
+ type: object
+ required:
+ - ContentType
+ properties:
+ ContentType:
+ $ref: "#/components/schemas/ContentType"
+ ContentTypeCreate:
+ description: This class is used to create a content type.
+ type: object
+ required:
+ - identifier
+ - mainLanguageCode
+ - remoteId
+ - urlAliasSchema
+ - nameSchema
+ - isContainer
+ - defaultSortField
+ - defaultSortOrder
+ - defaultAlwaysAvailable
+ - names
+ - descriptions
+ properties:
+ identifier:
+ type: string
+ mainLanguageCode:
+ type: string
+ remoteId:
+ type: string
+ urlAliasSchema:
+ type: string
+ nameSchema:
+ type: string
+ isContainer:
+ type: boolean
+ defaultSortField:
+ description: Specifies which property the child Locations should be sorted on by default when created.
+ defaultSortOrder:
+ description: Specifies whether the sort order should be ascending or descending by default when created.
+ defaultAlwaysAvailable:
+ type: boolean
+ names:
+ type:
+ $ref: "#/components/schemas/ValueObject"
+ descriptions:
+ type:
+ $ref: "#/components/schemas/ValueObject"
+ FieldDefinition:
+ type:
+ $ref: "#/components/schemas/FieldDefinition"
+ creatorId:
+ description: If set, this value overrides the current user as creator.
+ creationDate:
+ type: string
+ format: date-time
+ ContentTypeCreateWrapper:
+ type: object
+ required:
+ - ContentTypeCreate
+ properties:
+ ContentTypeCreate:
+ $ref: "#/components/schemas/ContentTypeCreate"
+ ContentTypeUpdateStruct:
+ description: This class is used for updating a content type.
+ type: object
+ properties:
+ identifier:
+ description: If set the unique identifier of a type is changed to this value.
+ type: string
+ remoteId:
+ description: If set the remote ID is changed to this value.
+ type: string
+ urlAliasSchema:
+ description: If set the URL alias schema is changed to this value.
+ type: string
+ nameSchema:
+ description: f set the name schema is changed to this value.
+ type: string
+ isContainer:
+ description: If set the container flag is set to this value.
+ type: boolean
+ mainLanguageCode:
+ description: If set the main language is changed to this value.
+ type: string
+ defaultSortField:
+ description: If set the default sort field is changed to this value.
+ enum:
+ - PATH
+ - PUBLISHED
+ - MODIFIED
+ - SECTION
+ - DEPTH
+ - PRIORITY
+ - NAME
+ - NODE_ID
+ - CONTENTOBJECT_ID
+ type: string
+ defaultSortOrder:
+ description: If set the default sort order is set to this value.
+ enum:
+ - ASC
+ - DESC
+ type: string
+ defaultAlwaysAvailable:
+ description: If set the default always available flag is set to this value.
+ type: boolean
+ modifierId:
+ description: If set this value overrides the current User as creator.
+ type: integer
+ modificationDate:
+ description: If set this value overrides the current time for creation.
+ type: string
+ format: date-time
+ names:
+ description: If set this array of names with languageCode keys replace the complete name collection.
+ descriptions:
+ description: If set this array of descriptions with languageCode keys replace the complete description collection.
+ ContentTypeUpdate:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is used to update a content type.
+ type: object
+ properties:
+ identifier:
+ type: string
+ mainLanguageCode:
+ type: string
+ remoteId:
+ type: string
+ urlAliasSchema:
+ type: [ string, 'null' ]
+ nameSchema:
+ type: string
+ isContainer:
+ type: boolean
+ defaultSortField:
+ description: Specifies which property the child Locations should be sorted on by default when updated.
+ defaultSortOrder:
+ description: Specifies whether the sort order should be ascending or descending by default when updated.
+ defaultAlwaysAvailable:
+ type: [ string, boolean ]
+ names:
+ type:
+ $ref: "#/components/schemas/ValueObject"
+ descriptions:
+ type:
+ $ref: "#/components/schemas/ValueObject"
+ modifierId:
+ description: If set, this value overrides the current user as creator.
+ modificationDate:
+ type: string
+ format: date-time
+ ContentTypeUpdateWrapper:
+ type: object
+ required:
+ - ContentTypeUpdate
+ properties:
+ ContentTypeUpdate:
+ $ref: "#/components/schemas/ContentTypeUpdate"
+ ContentTypeList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of content types.
+ type: object
+ required:
+ - ContentType
+ properties:
+ ContentType:
+ type: array
+ items:
+ $ref: "#/components/schemas/ContentType"
+ ContentTypeListWrapper:
+ type: object
+ required:
+ - ContentTypeList
+ properties:
+ ContentTypeList:
+ $ref: "#/components/schemas/ContentTypeList"
+ ContentTypeInfo:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class stores content type information.
+ type: object
+ required:
+ - id
+ - status
+ - identifier
+ - names
+ - descriptions
+ - creationDate
+ - modificationDate
+ - Creator
+ - Modifier
+ - Groups
+ - Draft
+ - remoteId
+ - urlAliasSchema
+ - nameSchema
+ - isContainer
+ - mainLanguageCode
+ - defaultAlwaysAvailable
+ - defaultSortField
+ - defaultSortOrder
+ properties:
+ id:
+ description: Content type ID.
+ type: integer
+ status:
+ description: "The status of the content type. Possible values: const STATUS_DEFINED = 0; Status constant for defined (aka published) Type, const STATUS_DRAFT = 1; Status constant for draft (aka temporary) Type; const STATUS_MODIFIED = 2; Status constant for modified (aka deferred for publishing) Type."
+ enum:
+ - DEFINED
+ - DRAFT
+ - MODIFIED
+ - PUBLISHED
+ type: string
+ identifier:
+ description: String identifier of a content type.
+ type: string
+ names:
+ description: Name of a content type.
+ descriptions:
+ description: Description of a content type.
+ creationDate:
+ description: Creation date of the content type.
+ type: string
+ format: date-time
+ modificationDate:
+ description: Modification date of the content type.
+ type: string
+ format: date-time
+ Creator:
+ description: Creator User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Modifier:
+ description: Modifier User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Groups:
+ description: Group User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Draft:
+ description: Draft of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ remoteId:
+ description: Unique remote ID of the content type.
+ type: string
+ urlAliasSchema:
+ description: URL alias schema. If nothing is provided, $nameSchema will be used instead.
+ type: [ string, 'null' ]
+ nameSchema:
+ description: Name schema. Can be composed of FieldDefinition identifier place holders.
+ type: string
+ isContainer:
+ description: A flag used to hint if content of this type may have children or not. It is highly recommended to respect this flag and not create/move content below non-containers. But this flag is not considered as part of the content model and the API will not in any way enforce this flag to be respected.
+ type: boolean
+ mainLanguageCode:
+ description: Main language code.
+ type: string
+ defaultAlwaysAvailable:
+ description: If an instance of a content type is created the always available flag is set by default to this value.
+ type: boolean
+ defaultSortField:
+ description: "Specifies which property the child Locations should be sorted on by default when created. Map for Location sort fields to their respective SortClauses - class name/identifier and modified subnode. One of the fallowing values: const SORT_FIELD_PATH = 1; const SORT_FIELD_PUBLISHED = 2; const SORT_FIELD_MODIFIED = 3; const SORT_FIELD_SECTION = 4; const SORT_FIELD_DEPTH = 5; const SORT_FIELD_PRIORITY = 8; const SORT_FIELD_NAME = 9; const SORT_FIELD_NODE_ID = 11; const SORT_FIELD_CONTENTOBJECT_ID = 12."
+ enum:
+ - PATH
+ - PUBLISHED
+ - MODIFIED
+ - SECTION
+ - DEPTH
+ - PRIORITY
+ - NAME
+ - NODE_ID
+ - CONTENTOBJECT_ID
+ type: string
+ defaultSortOrder:
+ description: "Specifies whether the sort order should be ascending or descending by default when created. Map for Location sort order to their respective Query SORT constants. Possible values: const SORT_ORDER_DESC = 0; const SORT_ORDER_ASC = 1."
+ enum:
+ - ASC
+ - DESC
+ type: string
+ ContentTypeInfoWrapper:
+ type: object
+ required:
+ - ContentTypeInfo
+ properties:
+ ContentTypeInfo:
+ $ref: "#/components/schemas/ContentTypeInfo"
+ ContentTypeInfoList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of content type information.
+ type: object
+ required:
+ - ContentType
+ properties:
+ ContentType:
+ description: This class stores content type information.
+ type: array
+ items:
+ $ref: "#/components/schemas/ContentTypeInfo"
+ ContentTypeInfoListWrapper:
+ type: object
+ required:
+ - ContentTypeList
+ properties:
+ ContentTypeList:
+ $ref: "#/components/schemas/ContentTypeInfoList"
+ Field:
+ description: This class represents a field of a content item.
+ type: object
+ required:
+ - fieldDefinitionIdentifier
+ - fieldValue
+ properties:
+ id:
+ description: The field ID.
+ type: integer
+ fieldDefinitionIdentifier:
+ description: The Field definition identifier.
+ type: string
+ languageCode:
+ description: The language code.
+ type: string
+ fieldTypeIdentifier:
+ description: Field Type identifier.
+ type: string
+ fieldValue:
+ description: A Field Type value or a value type which can be converted by the corresponding field type.
+ FieldDefinition:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a Field definition.
+ type: object
+ required:
+ - id
+ - identifier
+ - fieldType
+ - fieldGroup
+ - position
+ - isTranslatable
+ - isRequired
+ - isInfoCollector
+ - defaultValue
+ - isSearchable
+ - names
+ - descriptions
+ - fieldSettings
+ - validatorConfiguration
+ properties:
+ id:
+ description: The unique ID of this Field definition.
+ type: integer
+ identifier:
+ description: Readable string identifier of a Field definition.
+ type: string
+ fieldType:
+ description: String identifier of the field type.
+ type: string
+ fieldGroup:
+ description: Field group name.
+ type: string
+ position:
+ description: The position of the Field definition in the content type.
+ type: integer
+ isTranslatable:
+ description: If the field is translatable.
+ type: boolean
+ isRequired:
+ description: Is the field required.
+ type: boolean
+ isInfoCollector:
+ description: The flag if this field is used for information collection.
+ type: boolean
+ defaultValue:
+ description: Default value of the field.
+ isSearchable:
+ description: Indicates if th the content is searchable by this attribute.
+ type: boolean
+ names:
+ description: Names of content types.
+ descriptions:
+ description: Descriptions of content types.
+ fieldSettings:
+ description: Settings for the Field definition supported by the field type.
+ validatorConfiguration:
+ description: Validator configuration of this Field definition supported by the field type.
+ type:
+ oneOf:
+ - StringLengthValidatorWrapper
+ - array
+ FieldDefinitionWrapper:
+ type: object
+ required:
+ - FieldDefinition
+ properties:
+ FieldDefinition:
+ $ref: "#/components/schemas/FieldDefinition"
+ FieldDefinitionCreate:
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ FieldDefinitionCreateWrapper:
+ type: object
+ required:
+ - FieldDefinitionCreate
+ properties:
+ FieldDefinitionCreate:
+ $ref: "#/components/schemas/FieldDefinitionCreate"
+ FieldDefinitionUpdate:
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ FieldDefinitionUpdateWrapper:
+ type: object
+ required:
+ - FieldDefinitionUpdate
+ properties:
+ FieldDefinitionUpdate:
+ $ref: "#/components/schemas/FieldDefinitionUpdate"
+ FieldDefinitions:
+ type: object
+ required:
+ - FieldDefinition
+ properties:
+ FieldDefinition:
+ type: array
+ items:
+ $ref: "#/components/schemas/FieldDefinition"
+ FieldDefinitionsWrapper:
+ type: object
+ required:
+ - FieldDefinitions
+ properties:
+ FieldDefinitions:
+ $ref: "#/components/schemas/FieldDefinitions"
+ StringLengthValidator:
+ description: Validator for checking min. and max. length of strings.
+ type: object
+ required:
+ - maxStringLength
+ - minStringLength
+ properties:
+ maxStringLength:
+ description: Maximum length of strings.
+ type: [ integer, null ]
+ minStringLength:
+ description: Minimum length of strings.
+ type: [ integer, null ]
+ StringLengthValidatorWrapper:
+ type: object
+ required:
+ - StringLengthValidator
+ properties:
+ StringLengthValidator:
+ $ref: "#/components/schemas/StringLengthValidator"
diff --git a/src/bundle/Resources/api_platform/schemas/content_url_aliases_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_url_aliases_schemas.yml
new file mode 100644
index 000000000..2d5432c40
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_url_aliases_schemas.yml
@@ -0,0 +1,104 @@
+schemas:
+ UrlAlias:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a URL alias in the Repository.
+ type: object
+ required:
+ - _id
+ - _type
+ - resource
+ - path
+ - languageCodes
+ - alwaysAvailable
+ - isHistory
+ - forward
+ - custom
+ properties:
+ _id:
+ description: A unique identifier for the alias.
+ xml:
+ attribute: true
+ name: id
+ type: string
+ _type:
+ description: The type of the URL Alias i.e. one of URLAlias::LOCATION=0, URLAlias::RESOURCE=1, URLAlias::VIRTUAL=2.
+ enum:
+ - LOCATION
+ - RESOURCE
+ - VIRTUAL
+ xml:
+ attribute: true
+ name: type
+ type: string
+ resource:
+ description: If type = URLAlias::LOCATION it is a Location ID otherwise a string (e.g. /content/search).
+ path:
+ description: The full path of the alias.
+ type: string
+ languageCodes:
+ description: The languageCodes for which this path is valid.
+ type: string
+ alwaysAvailable:
+ description: Fallback indicator for other languages.
+ type: boolean
+ isHistory:
+ description: Indicates that this alias was autogenerated for an in the meanwhile archived version of the content.
+ type: boolean
+ forward:
+ description: Indicates if the URL should be redirected.
+ type: boolean
+ custom:
+ description: If false this alias was autogenerated otherwise manually created.
+ type: boolean
+ UrlAliasWrapper:
+ type: object
+ required:
+ - UrlAlias
+ properties:
+ UrlAlias:
+ $ref: "#/components/schemas/UrlAlias"
+ UrlAliasCreate:
+ type: object
+ required:
+ - _type
+ properties:
+ _type:
+ type: string
+ location:
+ type:
+ $ref: "#/components/schemas/Href"
+ resource:
+ type: string
+ languageCode:
+ type: string
+ alwaysAvailable:
+ type: [ string, boolean ]
+ forward:
+ type: [ string, boolean ]
+ UrlAliasCreateWrapper:
+ type: object
+ required:
+ - UrlAliasCreate
+ properties:
+ UrlAliasCreate:
+ $ref: "#/components/schemas/UrlAliasCreate"
+ UrlAliasRefList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of URL alias in the Repository.
+ type: object
+ required:
+ - UrlAlias
+ properties:
+ UrlAlias:
+ type: array
+ items:
+ $ref: "#/components/schemas/Ref"
+ UrlAliasRefListWrapper:
+ type: object
+ required:
+ - UrlAliasRefList
+ properties:
+ UrlAliasRefList:
+ $ref: "#/components/schemas/UrlAliasRefList"
diff --git a/src/bundle/Resources/api_platform/schemas/content_url_wildcards_schemas.yml b/src/bundle/Resources/api_platform/schemas/content_url_wildcards_schemas.yml
new file mode 100644
index 000000000..b360d37a6
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/content_url_wildcards_schemas.yml
@@ -0,0 +1,74 @@
+schemas:
+ UrlWildcard:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a URL alias in the Repository.
+ type: object
+ required:
+ - _id
+ - sourceUrl
+ - destinationUrl
+ - forward
+ properties:
+ _id:
+ description: The unique ID.
+ xml:
+ attribute: true
+ name: id
+ type: integer
+ sourceUrl:
+ description: The source URL.
+ type: string
+ destinationUrl:
+ description: The destination URL containing placeholders e.g. /destination/{1}.
+ type: string
+ forward:
+ description: Indicates if the URL is redirected or not.
+ type: boolean
+ UrlWildcardWrapper:
+ type: object
+ required:
+ - UrlWildcard
+ properties:
+ UrlWildcard:
+ $ref: "#/components/schemas/UrlWildcard"
+ UrlWildcardCreate:
+ description: Creates a new URL wildcard.
+ type: object
+ required:
+ - sourceUrl
+ - destinationUrl
+ - forward
+ properties:
+ sourceUrl:
+ type: string
+ destinationUrl:
+ type: string
+ forward:
+ type: [ string, boolean ]
+ UrlWildcardCreateWrapper:
+ type: object
+ required:
+ - URLWildcardCreate
+ properties:
+ URLWildcardCreate:
+ $ref: "#/components/schemas/UrlWildcardCreate"
+ UrlWildcardList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of URL alias in the Repository.
+ type: object
+ required:
+ - UrlWildcard
+ properties:
+ UrlWildcard:
+ type: array
+ items:
+ $ref: "#/components/schemas/UrlWildcard"
+ UrlWildcardListWrapper:
+ type: object
+ required:
+ - UrlWildcardList
+ properties:
+ UrlWildcardList:
+ $ref: "#/components/schemas/UrlWildcardList"
diff --git a/src/bundle/Resources/api_platform/language_schemas.yml b/src/bundle/Resources/api_platform/schemas/language_schemas.yml
similarity index 100%
rename from src/bundle/Resources/api_platform/language_schemas.yml
rename to src/bundle/Resources/api_platform/schemas/language_schemas.yml
diff --git a/src/bundle/Resources/api_platform/schemas/object_state_groups_schemas.yml b/src/bundle/Resources/api_platform/schemas/object_state_groups_schemas.yml
new file mode 100644
index 000000000..5209ab18f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/object_state_groups_schemas.yml
@@ -0,0 +1,240 @@
+schemas:
+ ObjectState:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a Object state value.
+ type: object
+ required:
+ - id
+ - identifier
+ - priority
+ - ObjectStateGroup
+ - languageCodes
+ - names
+ - descriptions
+ properties:
+ id:
+ description: Primary key.
+ type: integer
+ identifier:
+ description: Readable string identifier of the Object state.
+ type: string
+ priority:
+ description: Priority for ordering.
+ type: integer
+ ObjectStateGroup:
+ description: The Object state group this Object state belongs to.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ languageCodes:
+ description: The available language codes for names an descriptions.
+ type: string
+ names:
+ description: Names.
+ descriptions:
+ description: Descriptions.
+ ObjectStateWrapper:
+ type: object
+ required:
+ - ObjectState
+ properties:
+ ObjectState:
+ $ref: "#/components/schemas/ObjectState"
+ ObjectStateCreate:
+ description: This class represents a value for creating Object states.
+ type: object
+ required:
+ - identifier
+ - priority
+ - defaultLanguageCode
+ - languageCodes
+ - names
+ - descriptions
+ properties:
+ identifier:
+ description: Readable unique string identifier of a group.
+ type: string
+ priority:
+ description: Priority for ordering. If not set the Object state is created as the last one.
+ type: string
+ defaultLanguageCode:
+ description: The default language code.
+ type: string
+ languageCodes:
+ description: Language codes.
+ type: string
+ names:
+ description: An array of names with languageCode keys. At least one name in the main language is required.
+ type: object
+ required:
+ - value
+ properties:
+ value:
+ type: array
+ items:
+ $ref: "#/components/schemas/Value"
+ descriptions:
+ description: An array of descriptions with languageCode keys.
+ type: object
+ required:
+ - value
+ properties:
+ value:
+ type: array
+ items:
+ $ref: "#/components/schemas/Value"
+ ObjectStateCreateWrapper:
+ type: object
+ required:
+ - ObjectStateCreate
+ properties:
+ ObjectStateCreate:
+ $ref: "#/components/schemas/ObjectStateCreate"
+ ObjectStateUpdate:
+ description: This class represents a value for updating Object states.
+ type: object
+ properties:
+ identifier:
+ description: Readable unique string identifier of a group.
+ type: string
+ defaultLanguageCode:
+ description: The default language code.
+ type: string
+ names:
+ description: An array of names with languageCode keys.
+ descriptions:
+ description: An array of descriptions with languageCode keys.
+ ObjectStateUpdateWrapper:
+ type: object
+ required:
+ - ObjectStateUpdate
+ properties:
+ ObjectStateUpdate:
+ $ref: "#/components/schemas/ObjectStateUpdate"
+ ObjectStateList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of Object states.
+ type: object
+ required:
+ - ObjectState
+ properties:
+ ObjectState:
+ type: array
+ items:
+ $ref: "#/components/schemas/ObjectState"
+ ObjectStateListWrapper:
+ type: object
+ required:
+ - ObjectStateList
+ properties:
+ ObjectStateList:
+ $ref: "#/components/schemas/ObjectStateList"
+ ObjectStateGroup:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents an Object state group value.
+ type: object
+ required:
+ - id
+ - identifier
+ - defaultLanguageCode
+ - languageCodes
+ - ObjectStates
+ - names
+ - descriptions
+ properties:
+ id:
+ description: Primary key.
+ type: integer
+ identifier:
+ description: Readable string identifier of a group.
+ type: string
+ defaultLanguageCode:
+ description: The default language code.
+ type: string
+ languageCodes:
+ description: The available language codes for names an descriptions.
+ type: string
+ ObjectStates:
+ description: Object States.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ names:
+ description: List of names.
+ descriptions:
+ description: List of descriptions.
+ ObjectStateGroupWrapper:
+ type: object
+ required:
+ - ObjectStateGroup
+ properties:
+ ObjectStateGroup:
+ $ref: "#/components/schemas/ObjectStateGroup"
+ ObjectStateGroupCreate:
+ description: This class represents a value for creating Object state groups.
+ type: object
+ required:
+ - identifier
+ - defaultLanguageCode
+ - names
+ - descriptions
+ properties:
+ identifier:
+ description: Readable unique string identifier of a group.
+ type: string
+ defaultLanguageCode:
+ description: The default language code.
+ type: string
+ names:
+ description: An array of names with languageCode keys. At least one name in the main language is required.
+ descriptions:
+ description: An array of descriptions with languageCode keys.
+ ObjectStateGroupCreateWrapper:
+ type: object
+ required:
+ - ObjectStateGroupCreate
+ properties:
+ ObjectStateGroupCreate:
+ $ref: "#/components/schemas/ObjectStateGroupCreate"
+ ObjectStateGroupUpdate:
+ description: This class represents a value for updating Object state groups.
+ type: object
+ properties:
+ identifier:
+ description: Readable unique string identifier of a group.
+ type: string
+ defaultLanguageCode:
+ description: The default language code.
+ type: string
+ names:
+ description: An array of names with languageCode keys.
+ descriptions:
+ description: An array of descriptions with languageCode keys.
+ ObjectStateGroupUpdateWrapper:
+ type: object
+ required:
+ - ObjectStateGroupUpdate
+ properties:
+ ObjectStateGroupUpdate:
+ $ref: "#/components/schemas/ObjectStateGroupUpdate"
+ ObjectStateGroupList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of Object state groups.
+ type: object
+ required:
+ - ObjectStateGroup
+ properties:
+ ObjectStateGroup:
+ description: This class represents an Object state group value.
+ type: array
+ items:
+ $ref: "#/components/schemas/ObjectStateGroup"
+ ObjectStateGroupListWrapper:
+ type: object
+ required:
+ - ObjectStateGroupList
+ properties:
+ ObjectStateGroupList:
+ $ref: "#/components/schemas/ObjectStateGroupList"
diff --git a/src/bundle/Resources/api_platform/schemas/root_schemas.yml b/src/bundle/Resources/api_platform/schemas/root_schemas.yml
new file mode 100644
index 000000000..b01950808
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/root_schemas.yml
@@ -0,0 +1,141 @@
+schemas:
+ Root:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a root.
+ type: object
+ required:
+ - content
+ - contentByRemoteId
+ - contentTypes
+ - contentTypeByIdentifier
+ - contentTypeGroups
+ - contentTypeGroupByIdentifier
+ - users
+ - roles
+ - rootLocation
+ - rootUserGroup
+ - rootMediaFolder
+ - locationByRemoteId
+ - locationByPath
+ - trash
+ - sections
+ - views
+ - objectStateGroups
+ - objectStates
+ - globalUrlAliases
+ - urlWildcards
+ - createSession
+ - $refreshSession
+ properties:
+ content:
+ description: Content.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ contentByRemoteId:
+ description: Content by the given remote ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ contentTypes:
+ description: Content types.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ contentTypeByIdentifier:
+ description: Content type by the given identifier.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ contentTypeGroups:
+ description: Content type Groups.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ contentTypeGroupByIdentifier:
+ description: Content type Groups by the given identifier.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ users:
+ description: Users.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ usersByRoleId:
+ description: Users by Role ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ usersByRemoteId:
+ description: Users by remote ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ usersByEmail:
+ description: Users by e-mail.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ usersByLogin:
+ description: Users by login.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ roles:
+ description: Roles.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ rootLocation:
+ description: Root Location.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ rootUserGroup:
+ description: Root User Group.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ rootMediaFolder:
+ description: Root media folder.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ locationByRemoteId:
+ description: Location by remote ID.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ locationByPath:
+ description: Location by path.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ trash:
+ description: Trash.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ sections:
+ description: Sections.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ views:
+ description: Views.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ objectStateGroups:
+ description: Object state groups.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ objectStates:
+ description: Object states.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ globalUrlAliases:
+ description: Global URL aliases.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ urlWildcards:
+ description: URL Wildcards.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ createSession:
+ description: Creates a new session based on the credentials provided as POST parameters.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ refreshSession:
+ description: Refresh given session.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ RootWrapper:
+ type: object
+ required:
+ - Root
+ properties:
+ Root:
+ $ref: "#/components/schemas/Root"
diff --git a/src/bundle/Resources/api_platform/schemas/services_schemas.yml b/src/bundle/Resources/api_platform/schemas/services_schemas.yml
new file mode 100644
index 000000000..375ccec10
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/services_schemas.yml
@@ -0,0 +1,50 @@
+schemas:
+ CountryList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is representing an ISO-3166 formatted list of world countries.
+ type: object
+ required:
+ - Country
+ properties:
+ Country:
+ type: array
+ items:
+ $ref: "#/components/schemas/Country"
+ Country:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is representing a country.
+ type: object
+ required:
+ - _id
+ - name
+ - Alpha2
+ - Alpha3
+ - IDC
+ properties:
+ _id:
+ description: ID that represents a country name.
+ xml:
+ attribute: true
+ name: id
+ type: string
+ name:
+ description: Name of the country.
+ type: string
+ Alpha2:
+ description: Two-letter code that represents a country name.
+ type: string
+ Alpha3:
+ description: Three-letter code that represents a country name.
+ type: string
+ IDC:
+ description: IDC
+ type: integer
+ CountryListWrapper:
+ type: object
+ required:
+ - CountryList
+ properties:
+ CountryList:
+ $ref: "#/components/schemas/CountryList"
diff --git a/src/bundle/Resources/api_platform/schemas/user/roles_schemas.yml b/src/bundle/Resources/api_platform/schemas/user/roles_schemas.yml
new file mode 100644
index 000000000..88672bb0c
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/user/roles_schemas.yml
@@ -0,0 +1,273 @@
+schemas:
+ Role:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a role.
+ type: object
+ required:
+ - identifier
+ - Policies
+ properties:
+ identifier:
+ description: Readable string identifier of a role.
+ type: string
+ Policies:
+ description: Returns the list of policies of this role.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ RoleWrapper:
+ type: object
+ required:
+ - Role
+ properties:
+ Role:
+ $ref: "#/components/schemas/Role"
+ RoleDraft:
+ description: This class represents a draft of a role, extends Role.
+ type:
+ $ref: "#/components/schemas/Role"
+ RoleDraftWrapper:
+ type: object
+ required:
+ - Role
+ properties:
+ Role:
+ $ref: "#/components/schemas/RoleDraft"
+ RoleInput:
+ description: This class represents a Role input.
+ type: object
+ required:
+ - identifier
+ properties:
+ identifier:
+ type: string
+ RoleInputWrapper:
+ type: object
+ required:
+ - RoleInput
+ properties:
+ RoleInput:
+ $ref: "#/components/schemas/RoleInput"
+ RoleList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a list roles.
+ type: object
+ required:
+ - Role
+ properties:
+ Role:
+ type: array
+ items:
+ $ref: "#/components/schemas/Role"
+ RoleListWrapper:
+ type: object
+ required:
+ - RoleList
+ properties:
+ RoleList:
+ $ref: "#/components/schemas/RoleList"
+ Policy:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a policy value.
+ type: object
+ required:
+ - id
+ - module
+ - function
+ properties:
+ id:
+ description: ID of the policy.
+ type: integer
+ module:
+ description: Name of module, associated with the Policy e.g. content.
+ type: string
+ function:
+ description: Name of the module function Or all functions with '*' e.g. read.
+ type: string
+ limitations:
+ description: Limitations.
+ type: object
+ required:
+ - limitation
+ properties:
+ limitation:
+ type: array
+ items:
+ $ref: "#/components/schemas/Limitation"
+ PolicyWrapper:
+ type: object
+ required:
+ - Policy
+ properties:
+ Policy:
+ $ref: "#/components/schemas/Policy"
+ Limitation:
+ description: This class represents a Limitation applied to a policy.
+ type: object
+ required:
+ - _identifier
+ - values
+ properties:
+ _identifier:
+ description: "Returns the limitation identifier (one of the defined constants) or a custom limitation. Constants: CONTENTTYPE = Class; LANGUAGE = Language; LOCATION = Node; OWNER = Owner; PARENTOWNER = ParentOwner; PARENTCONTENTTYPE = ParentClass; PARENTDEPTH = ParentDepth; SECTION = Section; NEWSECTION = NewSection; SITEACCESS = SiteAccess; STATE = State; NEWSTATE = NewState; SUBTREE = Subtree; USERGROUP = Group; PARENTUSERGROUP = ParentGroup; STATUS = Status."
+ enum:
+ - ContentType
+ - Language
+ - Location
+ - Owner
+ - Parentowner
+ - ParentContentType
+ - ParentDepth
+ - Section
+ - NewSection
+ - SiteAccess
+ - State
+ - NewState
+ - Subtree
+ - UserGroup
+ - ParentUserGroup
+ - Status
+ - Class
+ xml:
+ attribute: true
+ name: identifier
+ type: string
+ values:
+ description: A read-only list of IDs or identifiers for which the limitation should be applied. The value of this property must conform to a hash, which means that it may only consist of array and scalar values, but must not contain objects or resources.
+ type: object
+ required:
+ - $ref
+ properties:
+ ref:
+ type: array
+ items:
+ $ref: "#/components/schemas/Ref"
+ PolicyList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: List of policies.
+ type: object
+ required:
+ - Policy
+ properties:
+ Policy:
+ type: array
+ items:
+ $ref: "#/components/schemas/Policy"
+ PolicyListWrapper:
+ type: object
+ required:
+ - PolicyList
+ properties:
+ PolicyList:
+ $ref: "#/components/schemas/PolicyList"
+ PolicyCreate:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is used to create a Policy.
+ type: object
+ required:
+ - module
+ - function
+ - Limitations
+ properties:
+ module:
+ description: Name of module associated with the Policy. For example, content.
+ type: string
+ function:
+ description: Name of the module function, or all functions with ''*''. For example, read.
+ type: string
+ Limitations:
+ type: array
+ items:
+ $ref: "#/components/schemas/Limitation"
+ PolicyCreateWrapper:
+ type: object
+ required:
+ - PolicyCreate
+ properties:
+ PolicyCreate:
+ $ref: "#/components/schemas/PolicyCreate"
+ PolicyUpdate:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class is used to update a Policy.
+ type: object
+ required:
+ - Limitations
+ properties:
+ Limitations:
+ type: array
+ items:
+ $ref: "#/components/schemas/Limitation"
+ PolicyUpdateWrapper:
+ type: object
+ required:
+ - PolicyUpdate
+ properties:
+ PolicyUpdate:
+ $ref: "#/components/schemas/PolicyUpdate"
+ RoleAssignment:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This value object represents an assignment of a User or User group to a role including a limitation.
+ type: object
+ required:
+ - Role
+ properties:
+ limitation:
+ description: Returns the limitation of the role assignment.
+ Role:
+ description: Returns the role to which the User or User group is assigned to.
+ type:
+ $ref: "#/components/schemas/Ref"
+ RoleAssignmentWrapper:
+ type: object
+ required:
+ - RoleAssignment
+ properties:
+ RoleAssignment:
+ $ref: "#/components/schemas/RoleAssignment"
+ RoleAssignInput:
+ description: This class represents a Role assign input.
+ type: object
+ required:
+ - Role
+ - limitation
+ properties:
+ Role:
+ description: Returns the Role to which the user or user group is assigned to.
+ type:
+ $ref: "#/components/schemas/Ref"
+ limitation:
+ description: Returns the Limitation of the Role assignment.
+ type:
+ $ref: "#/components/schemas/Limitation"
+ RoleAssignInputWrapper:
+ type: object
+ required:
+ - RoleAssignInput
+ properties:
+ RoleAssignInput:
+ $ref: "#/components/schemas/RoleAssignInput"
+ RoleAssignmentList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This value object represents a list of assignments of a User or User group to a role including a limitation.
+ type: object
+ required:
+ - RoleAssignment
+ properties:
+ RoleAssignment:
+ type: array
+ items:
+ $ref: "#/components/schemas/RoleAssignment"
+ RoleAssignmentListWrapper:
+ type: object
+ required:
+ - RoleAssignmentList
+ properties:
+ RoleAssignmentList:
+ $ref: "#/components/schemas/RoleAssignmentList"
diff --git a/src/bundle/Resources/api_platform/schemas/user/sessions_schemas.yml b/src/bundle/Resources/api_platform/schemas/user/sessions_schemas.yml
new file mode 100644
index 000000000..045877d8f
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/user/sessions_schemas.yml
@@ -0,0 +1,52 @@
+schemas:
+ Session:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Value for session.
+ type: object
+ required:
+ - name
+ - identifier
+ - csrfToken
+ - User
+ properties:
+ name:
+ description: Name.
+ type: string
+ identifier:
+ description: Identifier.
+ type: string
+ csrfToken:
+ description: csrfToken.
+ type: string
+ User:
+ description: User.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ SessionWrapper:
+ type: object
+ required:
+ - Session
+ properties:
+ Session:
+ $ref: "#/components/schemas/Session"
+ SessionInput:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a session input.
+ type: object
+ required:
+ - login
+ - password
+ properties:
+ login:
+ type: string
+ password:
+ type: string
+ SessionInputWrapper:
+ type: object
+ required:
+ - SessionInput
+ properties:
+ SessionInput:
+ $ref: "#/components/schemas/SessionInput"
diff --git a/src/bundle/Resources/api_platform/schemas/user/token_schemas.yml b/src/bundle/Resources/api_platform/schemas/user/token_schemas.yml
new file mode 100644
index 000000000..44d95555b
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/user/token_schemas.yml
@@ -0,0 +1,39 @@
+schemas:
+ JWT:
+ description: This class represents the JWT authentication token
+ type: object
+ required:
+ - token
+ properties:
+ token:
+ description: JWT authentication token
+ type: string
+ JWTWrapper:
+ type: object
+ required:
+ - JWT
+ properties:
+ JWT:
+ $ref: "#/components/schemas/JWT"
+ JWTInput:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents the input for a JWT authentication token
+ type: object
+ required:
+ - username
+ - password
+ properties:
+ username:
+ description: User name
+ type: string
+ password:
+ description: User password
+ type: string
+ JWTInputWrapper:
+ type: object
+ required:
+ - JWTInput
+ properties:
+ JWTInput:
+ $ref: "#/components/schemas/JWTInput"
diff --git a/src/bundle/Resources/api_platform/schemas/user/user_groups_schemas.yml b/src/bundle/Resources/api_platform/schemas/user/user_groups_schemas.yml
new file mode 100644
index 000000000..7f3d5163a
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/user/user_groups_schemas.yml
@@ -0,0 +1,192 @@
+schemas:
+ UserGroup:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Content ID matcher class.
+ type: object
+ required:
+ - _remoteId
+ - _id
+ - ContentType
+ - name
+ - Versions
+ - Section
+ - MainLocation
+ - Locations
+ - Owner
+ - lastModificationDate
+ - mainLanguageCode
+ - alwaysAvailable
+ - Version
+ - ParentUserGroup
+ - Subgroups
+ - Users
+ - Roles
+ properties:
+ _remoteId:
+ description: Remote ID of the content type.
+ xml:
+ attribute: true
+ name: remoteId
+ type: string
+ _id:
+ description: Unique ID of the content type.
+ xml:
+ attribute: true
+ name: id
+ type: integer
+ ContentType:
+ description: Content type.
+ type:
+ $ref: "#/components/schemas/Ref"
+ name:
+ type: string
+ Versions:
+ description: Returns the VersionInfo for this version.
+ type:
+ $ref: "#/components/schemas/Ref"
+ Section:
+ description: The Section to which the content item is assigned to.
+ type:
+ $ref: "#/components/schemas/Ref"
+ MainLocation:
+ type:
+ $ref: "#/components/schemas/Ref"
+ Locations:
+ description: Location of the content item.
+ type:
+ $ref: "#/components/schemas/Ref"
+ Owner:
+ description: The owner of the content item.
+ type:
+ $ref: "#/components/schemas/Ref"
+ lastModificationDate:
+ description: Content item modification date.
+ type: string
+ format: date-time
+ mainLanguageCode:
+ description: The main language code of the content item.
+ type: string
+ alwaysAvailable:
+ type: boolean
+ Version:
+ $ref: "#/components/schemas/Version"
+ ParentUserGroup:
+ type:
+ $ref: "#/components/schemas/Ref"
+ Subgroups:
+ type:
+ $ref: "#/components/schemas/Ref"
+ Users:
+ type:
+ $ref: "#/components/schemas/Ref"
+ Roles:
+ type:
+ $ref: "#/components/schemas/Ref"
+ UserGroupWrapper:
+ type: object
+ required:
+ - UserGroup
+ properties:
+ UserGroup:
+ $ref: "#/components/schemas/UserGroup"
+ UserGroupList:
+ description: This class represents a User Group list.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ UserGroupListWrapper:
+ type: object
+ required:
+ - UserGroupList
+ properties:
+ UserGroupList:
+ $ref: "#/components/schemas/UserGroupList"
+ UserGroupRefList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Returns a list of the sub groups.
+ type: object
+ required:
+ - UserGroup
+ properties:
+ UserGroup:
+ description: This class represents a User group.
+ type: array
+ items:
+ $ref: "#/components/schemas/Ref"
+ UserGroupRefListWrapper:
+ type: object
+ required:
+ - UserGroupRefList
+ properties:
+ UserGroupRefList:
+ $ref: "#/components/schemas/UserGroupRefList"
+ UserGroupCreate:
+ description: This class is used to create a User Group.
+ type: object
+ required:
+ - mainLanguageCode
+ - remoteId
+ - fields
+ properties:
+ mainLanguageCode:
+ type: string
+ remoteId:
+ type: string
+ fields:
+ type:
+ $ref: "#/components/schemas/Fields"
+ UserGroupCreateWrapper:
+ type: object
+ required:
+ - UserGroupCreate
+ properties:
+ UserGroupCreate:
+ $ref: "#/components/schemas/UserGroupCreate"
+ UserGroupUpdate:
+ description: This class is used to update a User group in the Repository.
+ type: object
+ required:
+ - Section
+ properties:
+ Section:
+ type: object
+ required:
+ - _href
+ properties:
+ _href:
+ xml:
+ attribute: true
+ name: href
+ type: string
+ UserGroupUpdateWrapper:
+ type: object
+ required:
+ - UserGroupUpdate
+ properties:
+ UserGroupUpdate:
+ $ref: "#/components/schemas/UserGroupUpdate"
+ UserGroupUnassign:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a User group.
+ type: object
+ required:
+ - Unassign
+ properties:
+ Unassign:
+ type:
+ $ref: "#/components/schemas/Unlink"
+ Unlink:
+ description: Unlink a content type group from a content type.
+ type: object
+ required:
+ - _href
+ - _method
+ properties:
+ _href:
+ type: string
+ _method:
+ enum:
+ - DELETE
+ type: string
diff --git a/src/bundle/Resources/api_platform/schemas/user/users_schemas.yml b/src/bundle/Resources/api_platform/schemas/user/users_schemas.yml
new file mode 100644
index 000000000..9d9902fa9
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/user/users_schemas.yml
@@ -0,0 +1,206 @@
+schemas:
+ User:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a User value.
+ type: object
+ required:
+ - _id
+ - _remoteId
+ - ContentType
+ - name
+ - Versions
+ - Section
+ - MainLocation
+ - Locations
+ - Groups
+ - Owner
+ - publishDate
+ - lastModificationDate
+ - mainLanguageCode
+ - alwaysAvailable
+ - Version
+ - login
+ - email
+ - enabled
+ - UserGroups
+ - Roles
+ properties:
+ _id:
+ description: Unique ID of the content type.
+ xml:
+ attribute: true
+ name: id
+ type: integer
+ _remoteId:
+ description: Remote ID of the content type.
+ xml:
+ attribute: true
+ name: remoteId
+ type: string
+ ContentType:
+ description: This class represents a content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ name:
+ description: Name of the domain object in a given language.
+ type: string
+ Versions:
+ description: Returns the VersionInfo for this version.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Section:
+ description: The Section to which the content item is assigned.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ MainLocation:
+ description: Main Location of the object.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Locations:
+ description: Locations of the object.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Groups:
+ description: Group User of the content type.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Owner:
+ description: The owner of the content item.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ publishDate:
+ description: Content publication date.
+ type: string
+ format: date-time
+ lastModificationDate:
+ description: Content modification date.
+ type: string
+ format: date-time
+ mainLanguageCode:
+ description: The main language code of the content item.
+ type: string
+ alwaysAvailable:
+ description: Indicates if the content item is shown in the main language if it's not present in an other requested language.
+ type: boolean
+ Version:
+ description: Returns the VersionInfo for this version.
+ login:
+ description: User login.
+ type: string
+ email:
+ description: User email address.
+ type: string
+ enabled:
+ description: Flag to Signal if User is enabled or not. User can not login if false.
+ type: boolean
+ UserGroups:
+ description: User groups.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ Roles:
+ description: Roles.
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ UserWrapper:
+ type: object
+ required:
+ - User
+ properties:
+ User:
+ $ref: "#/components/schemas/User"
+ UserList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: This class represents a list of users.
+ type: object
+ required:
+ - User
+ properties:
+ User:
+ type: array
+ items:
+ $ref: "#/components/schemas/User"
+ UserListWrapper:
+ type: object
+ required:
+ - UserList
+ properties:
+ UserList:
+ $ref: "#/components/schemas/UserList"
+ UserRefList:
+ allOf:
+ - $ref: "#/components/schemas/BaseObject"
+ - description: Returns a list of the users.
+ type: object
+ required:
+ - User
+ properties:
+ User:
+ description: This class represents a User.
+ type: array
+ items:
+ $ref: "#/components/schemas/BaseObject"
+ UserRefListWrapper:
+ type: object
+ required:
+ - UserRefList
+ properties:
+ UserRefList:
+ $ref: "#/components/schemas/UserRefList"
+ UserUpdate:
+ description: This class is used to update a User.
+ type: object
+ required:
+ - login
+ properties:
+ login:
+ type: string
+ email:
+ type: string
+ password:
+ type: string
+ enabled:
+ type: boolean
+ maxLogin:
+ type: integer
+ ContentUpdate:
+ description: The update structure for the profile content.
+ ContentMetadataUpdate:
+ description: The update structure for the profile metadata.
+ UserUpdateWrapper:
+ type: object
+ required:
+ - UserUpdate
+ properties:
+ UserUpdate:
+ $ref: "#/components/schemas/UserUpdate"
+ UserCreate:
+ description: This class is used to create a User.
+ type: object
+ required:
+ - mainLanguageCode
+ - remoteId
+ - login
+ - email
+ - password
+ properties:
+ mainLanguageCode:
+ type: string
+ remoteId:
+ type: string
+ login:
+ type: string
+ email:
+ type: string
+ password:
+ type: string
+ enabled:
+ type: boolean
+ UserCreateWrapper:
+ type: object
+ required:
+ - UserCreate
+ properties:
+ UserCreate:
+ $ref: "#/components/schemas/UserCreate"
diff --git a/src/bundle/Resources/api_platform/schemas/views_schemas.yml b/src/bundle/Resources/api_platform/schemas/views_schemas.yml
new file mode 100644
index 000000000..62c0b0467
--- /dev/null
+++ b/src/bundle/Resources/api_platform/schemas/views_schemas.yml
@@ -0,0 +1,151 @@
+schemas:
+ View:
+ description: View.
+ type: object
+ required:
+ - identifier
+ - User
+ - public
+ - LocationQuery
+ - Result
+ properties:
+ identifier:
+ description: Content identifier.
+ type: string
+ User:
+ type:
+ $ref: "#/components/schemas/User"
+ public:
+ type: boolean
+ LocationQuery:
+ type:
+ $ref: "#/components/schemas/LocationQuery"
+ Result:
+ type:
+ $ref: "#/components/schemas/BaseObject"
+ ViewInput:
+ description: This class represents a View input.
+ type: object
+ required:
+ - identifier
+ - Query
+ properties:
+ identifier:
+ description: Content identifier.
+ type: string
+ languageCode:
+ type: string
+ useAlwaysAvailable:
+ type: string
+ Query:
+ type:
+ $ref: "#/components/schemas/Query"
+ ViewInputWrapper:
+ type: object
+ required:
+ - ViewInput
+ properties:
+ ViewInput:
+ $ref: "#/components/schemas/ViewInput"
+ Query:
+ description: This class is used to perform a Content query.
+ type: object
+ properties:
+ Filter:
+ description: The Query filter. Can contain multiple criterion, as items of a logical one (by default AND).
+ type:
+ $ref: "#/components/schemas/Criterion"
+ Query:
+ description: The Query query. Can contain multiple criterion, as items of a logical one (by default AND).
+ type:
+ $ref: "#/components/schemas/Criterion"
+ sortClauses:
+ description: Query sorting clauses.
+ type: array
+ items:
+ $ref: "#/components/schemas/SortClause"
+ facetBuilders:
+ description: An array of facet builders. Search engines may ignore any, or given facet builders they don't support and will just return search result facets supported by the engine. API consumer should dynamically iterate over returned facets for further use.
+ type: array
+ items:
+ $ref: "#/components/schemas/FacetBuilder"
+ offset:
+ description: Query offset. Sets the offset for search hits, used for paging the results.
+ type: integer
+ limit:
+ description: Query limit. Limit for number of search hits to return. If value is `0`, search query will not return any search hits, useful for doing a count.
+ type: integer
+ spellcheck:
+ description: If true spellcheck suggestions are returned.
+ type: boolean
+ performCount:
+ description: If true, search engine should perform count even if that means extra lookup.
+ type: boolean
+ Criterion:
+ description: Criterion implementations.
+ type: object
+ properties:
+ operator:
+ description: The operator used by the Criterion.
+ type: string
+ value:
+ description: The value(s) matched by the Criteria.
+ type: array
+ items: { }
+ target:
+ description: The target used by the Criteria (field, metadata...).
+ type: string
+ valueData:
+ description: Additional value data, required by some Criteria, MapLocationDistance for instance.
+ Specifications:
+ description: Criterion description function. Returns the combination of the Criterion's supported operator/value, as an array of objects.
+ type: array
+ items:
+ $ref: "#/components/schemas/Specifications"
+ FacetBuilder:
+ description: This class is the base class for facet builders.
+ type: object
+ required:
+ - name
+ - global
+ - filter
+ - limit
+ - minCount
+ properties:
+ name:
+ description: The name of the facet.
+ type: string
+ global:
+ description: If true the facet runs in a global mode not restricted by the query.
+ type: boolean
+ filter:
+ description: An additional facet filter that will further filter the documents the facet will be executed on.
+ type:
+ $ref: "#/components/schemas/Criterion"
+ limit:
+ description: Number of facets (terms) returned.
+ type: integer
+ minCount:
+ description: Specifies the minimum count. Only facet groups with more or equal results are returned.
+ type: integer
+ Specifications:
+ description: This class is used by Criteria to describe which operators they support. Instances of this class are returned in an array by the {@see Criterion::getSpecifications()} method.
+ type: object
+ required:
+ - operator
+ - valueFormat
+ - valueTypes
+ - valueCount
+ properties:
+ operator:
+ description: Specified operator, as one of the Operator::* constants.
+ type: string
+ valueFormat:
+ description: Format supported for the Criterion value, either {@see self::FORMAT_SINGLE} for single or {@see self::FORMAT_ARRAY} for multiple.
+ type: string
+ valueTypes:
+ description: "Accepted values types, specifying what type of variables are accepted as a value. Criterion input value type description constants: const TYPE_INTEGER = 1; const TYPE_STRING = 2; const TYPE_BOOLEAN = 4."
+ type: integer
+ valueCount:
+ description: Limitation on the number of items as the value. Only usable if {@see $valueFormat} is {@see self::FORMAT_ARRAY}.
+ type: integer
diff --git a/src/bundle/Resources/config/api_platform.yml b/src/bundle/Resources/config/api_platform.yml
index 72925025c..3f9bc393c 100644
--- a/src/bundle/Resources/config/api_platform.yml
+++ b/src/bundle/Resources/config/api_platform.yml
@@ -39,5 +39,22 @@ services:
autoconfigure: true
arguments:
$files:
- - '@@IbexaRestBundle/Resources/api_platform/base_schemas.yml'
- - '@@IbexaRestBundle/Resources/api_platform/language_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/base_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/bookmarks_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_locations_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_objects_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_sections_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_trash_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_type_groups_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_types_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_url_aliases_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/content_url_wildcards_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/language_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/object_state_groups_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/services_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/views_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/user/roles_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/user/sessions_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/user/token_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/user/user_groups_schemas.yml'
+ - '@@IbexaRestBundle/Resources/api_platform/schemas/user/users_schemas.yml'
diff --git a/src/bundle/Resources/config/routing.yml b/src/bundle/Resources/config/routing.yml
index d85fccbca..ed4f865d7 100644
--- a/src/bundle/Resources/config/routing.yml
+++ b/src/bundle/Resources/config/routing.yml
@@ -18,31 +18,31 @@ ibexa.api_platform.documentation:
ibexa.rest.list_sections:
path: /content/sections
- controller: Ibexa\Rest\Server\Controller\Section::listSections
+ controller: Ibexa\Rest\Server\Controller\Section\SectionListController::listSections
methods: [GET]
ibexa.rest.create_section:
path: /content/sections
- controller: Ibexa\Rest\Server\Controller\Section::createSection
+ controller: Ibexa\Rest\Server\Controller\Section\SectionCreateController::createSection
methods: [POST]
ibexa.rest.load_section:
path: /content/sections/{sectionId}
- controller: Ibexa\Rest\Server\Controller\Section::loadSection
+ controller: Ibexa\Rest\Server\Controller\Section\SectionLoadByIdController::loadSection
methods: [GET]
requirements:
sectionId: \d+
ibexa.rest.update_section:
path: /content/sections/{sectionId}
- controller: Ibexa\Rest\Server\Controller\Section::updateSection
+ controller: Ibexa\Rest\Server\Controller\Section\SectionUpdateController::updateSection
methods: [PATCH]
requirements:
sectionId: \d+
ibexa.rest.delete_section:
path: /content/sections/{sectionId}
- controller: Ibexa\Rest\Server\Controller\Section::deleteSection
+ controller: Ibexa\Rest\Server\Controller\Section\SectionDeleteController::deleteSection
methods: [DELETE]
requirements:
sectionId: \d+
@@ -58,7 +58,7 @@ ibexa.rest.refresh_session:
ibexa.rest.content.copy:
path: /content/objects/{contentId}
- controller: Ibexa\Rest\Server\Controller\Content::copy
+ controller: Ibexa\Rest\Server\Controller\Content\ContentCopyController::copy
condition: 'ibexa_get_media_type(request) === "CopyContentInput"'
methods: [POST]
options:
@@ -68,7 +68,7 @@ ibexa.rest.content.copy:
ibexa.rest.content.create_draft_from_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::createDraftFromVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDraftCreateFromVersionController::createDraftFromVersion
condition: 'ibexa_get_media_type(request) === "CreateDraftFromVersionInput"'
methods: [POST]
options:
@@ -76,7 +76,7 @@ ibexa.rest.content.create_draft_from_version:
ibexa.rest.content.create_draft_from_current_version:
path: /content/objects/{contentId}/currentversion
- controller: Ibexa\Rest\Server\Controller\Content::createDraftFromCurrentVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDraftCreateFromCurrentVersionController::createDraftFromCurrentVersion
condition: 'ibexa_get_media_type(request) === "CreateDraftFromCurrentVersionInput"'
methods: [POST]
options:
@@ -86,7 +86,7 @@ ibexa.rest.content.create_draft_from_current_version:
ibexa.rest.content.publish_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::publishVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionPublishController::publishVersion
condition: 'ibexa_get_media_type(request) === "PublishContentVersionInput"'
methods: [POST]
options:
@@ -97,64 +97,64 @@ ibexa.rest.content.publish_version:
ibexa.rest.redirect_content:
path: /content/objects
- controller: Ibexa\Rest\Server\Controller\Content::redirectContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentRedirectController::redirectContent
methods: [GET]
ibexa.rest.create_content:
path: /content/objects
- controller: Ibexa\Rest\Server\Controller\Content::createContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentCreateController::createContent
methods: [POST]
ibexa.rest.update_content_metadata:
path: /content/objects/{contentId}
- controller: Ibexa\Rest\Server\Controller\Content::updateContentMetadata
+ controller: Ibexa\Rest\Server\Controller\Content\ContentMetadataUpdateController::updateContentMetadata
methods: [PATCH]
requirements:
contentId: \d+
ibexa.rest.load_content:
path: /content/objects/{contentId}
- controller: Ibexa\Rest\Server\Controller\Content::loadContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentLoadByIdController::loadContent
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.delete_content:
path: /content/objects/{contentId}
- controller: Ibexa\Rest\Server\Controller\Content::deleteContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDeleteController::deleteContent
methods: [DELETE]
requirements:
contentId: \d+
ibexa.rest.copy_content:
path: /content/objects/{contentId}
- controller: Ibexa\Rest\Server\Controller\Content::copyContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentCopyController::copyContent
methods: [COPY]
requirements:
contentId: \d+
ibexa.rest.delete_content_translation:
path: /content/objects/{contentId}/translations/{languageCode}
- controller: Ibexa\Rest\Server\Controller\Content::deleteContentTranslation
+ controller: Ibexa\Rest\Server\Controller\Content\ContentTranslationDeleteController::deleteContentTranslation
methods: [DELETE]
ibexa.rest.redirect_current_version_relations:
path: /content/objects/{contentId}/relations
- controller: Ibexa\Rest\Server\Controller\Content::redirectCurrentVersionRelations
+ controller: Ibexa\Rest\Server\Controller\Content\ContentCurrentVersionRelationsRedirectController::redirectCurrentVersionRelations
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.load_content_versions:
path: /content/objects/{contentId}/versions
- controller: Ibexa\Rest\Server\Controller\Content::loadContentVersions
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionsListController::loadContentVersions
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.load_version_relations:
path: /content/objects/{contentId}/versions/{versionNumber}/relations
- controller: Ibexa\Rest\Server\Controller\Content::loadVersionRelations
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionsRelationsListController::loadVersionRelations
methods: [GET]
requirements:
contentId: \d+
@@ -162,7 +162,7 @@ ibexa.rest.load_version_relations:
ibexa.rest.create_relation:
path: /content/objects/{contentId}/versions/{versionNumber}/relations
- controller: Ibexa\Rest\Server\Controller\Content::createRelation
+ controller: Ibexa\Rest\Server\Controller\Content\ContentRelationCreateController::createRelation
methods: [POST]
requirements:
contentId: \d+
@@ -170,7 +170,7 @@ ibexa.rest.create_relation:
ibexa.rest.load_version_relation:
path: /content/objects/{contentId}/versions/{versionNumber}/relations/{relationId}
- controller: Ibexa\Rest\Server\Controller\Content::loadVersionRelation
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionRelationLoadByIdController::loadVersionRelation
methods: [GET]
requirements:
contentId: \d+
@@ -179,7 +179,7 @@ ibexa.rest.load_version_relation:
ibexa.rest.remove_relation:
path: /content/objects/{contentId}/versions/{versionNumber}/relations/{relationId}
- controller: Ibexa\Rest\Server\Controller\Content::removeRelation
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionRelationDeleteController::removeRelation
methods: [DELETE]
requirements:
contentId: \d+
@@ -188,7 +188,7 @@ ibexa.rest.remove_relation:
ibexa.rest.load_content_in_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::loadContentInVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentInVersionLoadController::loadContentInVersion
methods: [GET]
requirements:
contentId: \d+
@@ -196,7 +196,7 @@ ibexa.rest.load_content_in_version:
ibexa.rest.update_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::updateVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionUpdateController::updateVersion
methods: [PATCH]
requirements:
contentId: \d+
@@ -204,7 +204,7 @@ ibexa.rest.update_version:
ibexa.rest.delete_content_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::deleteContentVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionDeleteController::deleteContentVersion
methods: [DELETE]
requirements:
contentId: \d+
@@ -212,7 +212,7 @@ ibexa.rest.delete_content_version:
ibexa.rest.delete_translation_from_draft:
path: /content/objects/{contentId}/versions/{versionNumber}/translations/{languageCode}
- controller: Ibexa\Rest\Server\Controller\Content::deleteTranslationFromDraft
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDraftTranslationDeleteController::deleteTranslationFromDraft
methods: [DELETE]
requirements:
contentId: \d+
@@ -220,7 +220,7 @@ ibexa.rest.delete_translation_from_draft:
ibexa.rest.create_draft_from_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::createDraftFromVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDraftCreateFromVersionController::createDraftFromVersion
methods: [COPY]
requirements:
contentId: \d+
@@ -228,7 +228,7 @@ ibexa.rest.create_draft_from_version:
ibexa.rest.publish_version:
path: /content/objects/{contentId}/versions/{versionNumber}
- controller: Ibexa\Rest\Server\Controller\Content::publishVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentVersionPublishController::publishVersion
methods: [PUBLISH]
requirements:
contentId: \d+
@@ -236,28 +236,28 @@ ibexa.rest.publish_version:
ibexa.rest.redirect_current_version:
path: /content/objects/{contentId}/currentversion
- controller: Ibexa\Rest\Server\Controller\Content::redirectCurrentVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentCurrentVersionRedirectController::redirectCurrentVersion
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.create_draft_from_current_version:
path: /content/objects/{contentId}/currentversion
- controller: Ibexa\Rest\Server\Controller\Content::createDraftFromCurrentVersion
+ controller: Ibexa\Rest\Server\Controller\Content\ContentDraftCreateFromCurrentVersionController::createDraftFromCurrentVersion
methods: [COPY]
requirements:
contentId: \d+
ibexa.rest.hide_content:
path: /content/objects/{contentId}/hide
- controller: Ibexa\Rest\Server\Controller\Content::hideContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentHideController::hideContent
methods: [POST]
requirements:
contentId: \d+
ibexa.rest.reveal_content:
path: /content/objects/{contentId}/reveal
- controller: Ibexa\Rest\Server\Controller\Content::revealContent
+ controller: Ibexa\Rest\Server\Controller\Content\ContentRevealController::revealContent
methods: [POST]
requirements:
contentId: \d+
@@ -297,52 +297,52 @@ ibexa.rest.views.load.results:
ibexa.rest.load_object_state_groups:
path: /content/objectstategroups
- controller: Ibexa\Rest\Server\Controller\ObjectState::loadObjectStateGroups
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupListController::loadObjectStateGroups
methods: [GET]
ibexa.rest.create_object_state_group:
path: /content/objectstategroups
- controller: Ibexa\Rest\Server\Controller\ObjectState::createObjectStateGroup
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupCreateController::createObjectStateGroup
methods: [POST]
ibexa.rest.load_object_state_group:
path: /content/objectstategroups/{objectStateGroupId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::loadObjectStateGroup
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupLoadByIdController::loadObjectStateGroup
methods: [GET]
requirements:
objectStateGroupId: \d+
ibexa.rest.update_object_state_group:
path: /content/objectstategroups/{objectStateGroupId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::updateObjectStateGroup
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupUpdateController::updateObjectStateGroup
methods: [PATCH]
requirements:
objectStateGroupId: \d+
ibexa.rest.delete_object_state_group:
path: /content/objectstategroups/{objectStateGroupId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::deleteObjectStateGroup
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupDeleteController::deleteObjectStateGroup
methods: [DELETE]
requirements:
objectStateGroupId: \d+
ibexa.rest.load_object_states:
path: /content/objectstategroups/{objectStateGroupId}/objectstates
- controller: Ibexa\Rest\Server\Controller\ObjectState::loadObjectStates
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateListController::loadObjectStates
methods: [GET]
requirements:
objectStateGroupId: \d+
ibexa.rest.create_object_state:
path: /content/objectstategroups/{objectStateGroupId}/objectstates
- controller: Ibexa\Rest\Server\Controller\ObjectState::createObjectState
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateCreateController::createObjectState
methods: [POST]
requirements:
objectStateGroupId: \d+
ibexa.rest.load_object_state:
path: /content/objectstategroups/{objectStateGroupId}/objectstates/{objectStateId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::loadObjectState
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateLoadByIdController::loadObjectState
methods: [GET]
requirements:
objectStateGroupId: \d+
@@ -350,7 +350,7 @@ ibexa.rest.load_object_state:
ibexa.rest.update_object_state:
path: /content/objectstategroups/{objectStateGroupId}/objectstates/{objectStateId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::updateObjectState
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateUpdateController::updateObjectState
methods: [PATCH]
requirements:
objectStateGroupId: \d+
@@ -358,7 +358,7 @@ ibexa.rest.update_object_state:
ibexa.rest.delete_object_state:
path: /content/objectstategroups/{objectStateGroupId}/objectstates/{objectStateId}
- controller: Ibexa\Rest\Server\Controller\ObjectState::deleteObjectState
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStateGroupDeleteController::deleteObjectState
methods: [DELETE]
requirements:
objectStateGroupId: \d+
@@ -366,14 +366,14 @@ ibexa.rest.delete_object_state:
ibexa.rest.get_object_states_for_content:
path: /content/objects/{contentId}/objectstates
- controller: Ibexa\Rest\Server\Controller\ObjectState::getObjectStatesForContent
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStatesForContnetListController::getObjectStatesForContent
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.set_object_states_for_content:
path: /content/objects/{contentId}/objectstates
- controller: Ibexa\Rest\Server\Controller\ObjectState::setObjectStatesForContent
+ controller: Ibexa\Rest\Server\Controller\ObjectState\ObjectStatesForContentUpdateController::setObjectStatesForContent
methods: [PATCH]
requirements:
contentId: \d+
@@ -384,18 +384,18 @@ ibexa.rest.set_object_states_for_content:
ibexa.rest.languages.list:
path: /languages
methods: [GET]
- controller: Ibexa\Rest\Server\Controller\Language::listLanguages
+ controller: Ibexa\Rest\Server\Controller\Language\LanguageListController::listLanguages
ibexa.rest.languages.view:
path: /languages/{languageCode}
methods: [GET]
- controller: Ibexa\Rest\Server\Controller\Language::loadLanguage
+ controller: Ibexa\Rest\Server\Controller\Language\LanguageLoadByIdController::loadLanguage
# Locations
ibexa.rest.location.copy:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::copy
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSubtreeCopyController::copy
condition: 'ibexa_get_media_type(request) === "CopyLocationInput"'
methods: [POST]
options:
@@ -405,7 +405,7 @@ ibexa.rest.location.copy:
ibexa.rest.trash_location:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Trash::trashLocation
+ controller: Ibexa\Rest\Server\Controller\Trash\LocationTrashController::trashLocation
condition: 'ibexa_get_media_type(request) === "TrashLocationInput"'
methods: [POST, TRASH]
options:
@@ -415,7 +415,7 @@ ibexa.rest.trash_location:
ibexa.rest.location.swap:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::swap
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSwapController::swap
condition: 'ibexa_get_media_type(request) === "SwapLocationInput"'
methods: [POST]
options:
@@ -425,7 +425,7 @@ ibexa.rest.location.swap:
ibexa.rest.location.move:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::moveLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSubtreeMoveController::moveLocation
condition: 'ibexa_get_media_type(request) === "MoveLocationInput"'
methods: [POST]
options:
@@ -435,68 +435,68 @@ ibexa.rest.location.move:
ibexa.rest.redirect_location:
path: /content/locations
- controller: Ibexa\Rest\Server\Controller\Location::redirectLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationRedirectController::redirectLocation
methods: [GET]
ibexa.rest.load_location:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::loadLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationLoadByPathController::loadLocation
methods: [GET]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.update_location:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::updateLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationUpdateController::updateLocation
methods: [PATCH]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.delete_subtree:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::deleteSubtree
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSubtreeDeleteController::deleteSubtree
methods: [DELETE]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.copy_subtree:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::copySubtree
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSubtreeCopyController::copySubtree
methods: [COPY]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.move_subtree:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::moveSubtree
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSubtreeMoveController::moveSubtree
methods: [MOVE]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.swap_location:
path: /content/locations/{locationPath}
- controller: Ibexa\Rest\Server\Controller\Location::swapLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationSwapController::swapLocation
methods: [SWAP]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.load_location_children:
path: /content/locations/{locationPath}/children
- controller: Ibexa\Rest\Server\Controller\Location::loadLocationChildren
+ controller: Ibexa\Rest\Server\Controller\Location\LocationChildrenListController::loadLocationChildren
methods: [GET]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.load_locations_for_content:
path: /content/objects/{contentId}/locations
- controller: Ibexa\Rest\Server\Controller\Location::loadLocationsForContent
+ controller: Ibexa\Rest\Server\Controller\Location\LocationForContentListController::loadLocationsForContent
methods: [GET]
requirements:
contentId: \d+
ibexa.rest.create_location:
path: /content/objects/{contentId}/locations
- controller: Ibexa\Rest\Server\Controller\Location::createLocation
+ controller: Ibexa\Rest\Server\Controller\Location\LocationCreateController::createLocation
methods: [POST]
requirements:
contentId: \d+
@@ -505,7 +505,7 @@ ibexa.rest.create_location:
ibexa.rest.content_type.publish_draft:
path: /content/types/{contentTypeId}/draft
- controller: Ibexa\Rest\Server\Controller\ContentType::publishContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftPublishController::publishContentTypeDraft
condition: 'ibexa_get_media_type(request) === "PublishContentTypeInput"'
methods: [POST]
options:
@@ -515,7 +515,7 @@ ibexa.rest.content_type.publish_draft:
ibexa.rest.content_type.copy:
path: /content/types/{contentTypeId}
- controller: Ibexa\Rest\Server\Controller\ContentType::copyContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeCopyController::copyContentType
condition: 'ibexa_get_media_type(request) === "CopyContentTypeInput"'
methods: [POST]
options:
@@ -525,45 +525,45 @@ ibexa.rest.content_type.copy:
ibexa.rest.load_content_type_group_list:
path: /content/typegroups
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeGroupList
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupsListController::loadContentTypeGroupList
methods: [GET]
ibexa.rest.create_content_type_group:
path: /content/typegroups
- controller: Ibexa\Rest\Server\Controller\ContentType::createContentTypeGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupCreateController::createContentTypeGroup
methods: [POST]
ibexa.rest.load_content_type_group:
path: /content/typegroups/{contentTypeGroupId}
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupLoadByIdController::loadContentTypeGroup
methods: [GET]
requirements:
contentTypeGroupId: \d+
ibexa.rest.update_content_type_group:
path: /content/typegroups/{contentTypeGroupId}
- controller: Ibexa\Rest\Server\Controller\ContentType::updateContentTypeGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupUpdateController::updateContentTypeGroup
methods: [PATCH]
requirements:
contentTypeGroupId: \d+
ibexa.rest.delete_content_type_group:
path: /content/typegroups/{contentTypeGroupId}
- controller: Ibexa\Rest\Server\Controller\ContentType::deleteContentTypeGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupDeleteController::deleteContentTypeGroup
methods: [DELETE]
requirements:
contentTypeGroupId: \d+
ibexa.rest.list_content_types_for_group:
path: /content/typegroups/{contentTypeGroupId}/types
- controller: Ibexa\Rest\Server\Controller\ContentType::listContentTypesForGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeListForGroupController::listContentTypesForGroup
methods: [GET]
requirements:
contentTypeGroupId: \d+
ibexa.rest.create_content_type:
path: /content/typegroups/{contentTypeGroupId}/types
- controller: Ibexa\Rest\Server\Controller\ContentType::createContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeCreateController::createContentType
methods: [POST]
requirements:
contentTypeGroupId: \d+
@@ -571,54 +571,54 @@ ibexa.rest.create_content_type:
ibexa.rest.list_content_types:
# @todo: Handle all GET parameters
path: /content/types
- controller: Ibexa\Rest\Server\Controller\ContentType::listContentTypes
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeListController::listContentTypes
methods: [GET]
ibexa.rest.copy_content_type:
path: /content/types/{contentTypeId}
- controller: Ibexa\Rest\Server\Controller\ContentType::copyContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeCopyController::copyContentType
methods: [COPY]
requirements:
contentTypeId: \d+
ibexa.rest.load_content_type:
path: /content/types/{contentTypeId}
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeLoadByIdController::loadContentType
methods: [GET]
requirements:
contentTypeId: \d+
ibexa.rest.create_content_type_draft:
path: /content/types/{contentTypeId}
- controller: Ibexa\Rest\Server\Controller\ContentType::createContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftCreateController::createContentTypeDraft
methods: [POST]
requirements:
contentTypeId: \d+
ibexa.rest.delete_content_type:
path: /content/types/{contentTypeId}
- controller: Ibexa\Rest\Server\Controller\ContentType::deleteContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDeleteController::deleteContentType
methods: [DELETE]
requirements:
contentTypeId: \d+
ibexa.rest.delete_content_type_draft:
path: /content/types/{contentTypeId}/draft
- controller: Ibexa\Rest\Server\Controller\ContentType::deleteContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftDeleteController::deleteContentTypeDraft
methods: [DELETE]
requirements:
contentTypeId: \d+
ibexa.rest.load_content_type_field_definition_list:
path: /content/types/{contentTypeId}/fieldDefinitions
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeFieldDefinitionList
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeFieldDefinitionListController::loadContentTypeFieldDefinitionList
methods: [GET]
requirements:
contentTypeId: \d+
ibexa.rest.load_content_type_field_definition:
path: /content/types/{contentTypeId}/fieldDefinitions/{fieldDefinitionId}
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeFieldDefinition
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeFieldDefinitionLoadByIdController::loadContentTypeFieldDefinition
methods: [GET]
requirements:
contentTypeId: \d+
@@ -626,7 +626,7 @@ ibexa.rest.load_content_type_field_definition:
ibexa.rest.load_content_type_field_definition_by_identifier:
path: /content/types/{contentTypeId}/fieldDefinition/{fieldDefinitionIdentifier}
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeFieldDefinitionByIdentifier
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeFieldDefinitionLoadByIdentifierController::loadContentTypeFieldDefinitionByIdentifier
methods: [GET]
requirements:
contentTypeId: \d+
@@ -634,42 +634,42 @@ ibexa.rest.load_content_type_field_definition_by_identifier:
ibexa.rest.load_content_type_draft:
path: /content/types/{contentTypeId}/draft
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftLoadController::loadContentTypeDraft
methods: [GET]
requirements:
contentTypeId: \d+
ibexa.rest.update_content_type_draft:
path: /content/types/{contentTypeId}/draft
- controller: Ibexa\Rest\Server\Controller\ContentType::updateContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftUpdateController::updateContentTypeDraft
methods: [PATCH]
requirements:
contentTypeId: \d+
ibexa.rest.publish_content_type_draft:
path: /content/types/{contentTypeId}/draft
- controller: Ibexa\Rest\Server\Controller\ContentType::publishContentTypeDraft
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftPublishController::publishContentTypeDraft
methods: [PUBLISH]
requirements:
contentTypeId: \d+
ibexa.rest.load_content_type_draft_field_definition_list:
path: /content/types/{contentTypeId}/draft/fieldDefinitions
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeDraftFieldDefinitionList
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftFieldDefinitionListController::loadContentTypeDraftFieldDefinitionList
methods: [GET]
requirements:
contentTypeId: \d+
ibexa.rest.add_content_type_draft_field_definition:
path: /content/types/{contentTypeId}/draft/fieldDefinitions
- controller: Ibexa\Rest\Server\Controller\ContentType::addContentTypeDraftFieldDefinition
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftFeildDefinitionAddController::addContentTypeDraftFieldDefinition
methods: [POST]
requirements:
contentTypeId: \d+
ibexa.rest.load_content_type_draft_field_definition:
path: /content/types/{contentTypeId}/draft/fieldDefinitions/{fieldDefinitionId}
- controller: Ibexa\Rest\Server\Controller\ContentType::loadContentTypeDraftFieldDefinition
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftFieldDefinitionLoadByIdController::loadContentTypeDraftFieldDefinition
methods: [GET]
requirements:
contentTypeId: \d+
@@ -677,7 +677,7 @@ ibexa.rest.load_content_type_draft_field_definition:
ibexa.rest.update_content_type_draft_field_definition:
path: /content/types/{contentTypeId}/draft/fieldDefinitions/{fieldDefinitionId}
- controller: Ibexa\Rest\Server\Controller\ContentType::updateContentTypeDraftFieldDefinition
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftFieldDefinitionUpdateController::updateContentTypeDraftFieldDefinition
methods: [PATCH]
requirements:
contentTypeId: \d+
@@ -685,7 +685,7 @@ ibexa.rest.update_content_type_draft_field_definition:
ibexa.rest.remove_content_type_draft_field_definition:
path: /content/types/{contentTypeId}/draft/fieldDefinitions/{fieldDefinitionId}
- controller: Ibexa\Rest\Server\Controller\ContentType::removeContentTypeDraftFieldDefinition
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeDraftFieldDefinitionDeleteController::removeContentTypeDraftFieldDefinition
methods: [DELETE]
requirements:
contentTypeId: \d+
@@ -693,7 +693,7 @@ ibexa.rest.remove_content_type_draft_field_definition:
ibexa.rest.load_groups_of_content_type:
path: /content/types/{contentTypeId}/groups
- controller: Ibexa\Rest\Server\Controller\ContentType::loadGroupsOfContentType
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeGroupListController::loadGroupsOfContentType
methods: [GET]
requirements:
contentTypeId: \d+
@@ -701,14 +701,14 @@ ibexa.rest.load_groups_of_content_type:
ibexa.rest.link_content_type_to_group:
# Handle GET parameter group in controller. Most likely already done
path: /content/types/{contentTypeId}/groups
- controller: Ibexa\Rest\Server\Controller\ContentType::linkContentTypeToGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeLinkToGroupController::linkContentTypeToGroup
methods: [POST]
requirements:
contentTypeId: \d+
ibexa.rest.unlink_content_type_from_group:
path: /content/types/{contentTypeId}/groups/{contentTypeGroupId}
- controller: Ibexa\Rest\Server\Controller\ContentType::unlinkContentTypeFromGroup
+ controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeUnlinkFromGroupController::unlinkContentTypeFromGroup
methods: [DELETE]
requirements:
contentTypeId: \d+
@@ -718,7 +718,7 @@ ibexa.rest.unlink_content_type_from_group:
ibexa.rest.trash.restore_trash_item:
path: /content/trash/{trashItemId}
- controller: Ibexa\Rest\Server\Controller\Trash::restoreItem
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashItemRestoreController::restoreItem
condition: 'ibexa_get_media_type(request) === "RestoreTrashItemInput"'
methods: [POST]
options:
@@ -728,31 +728,31 @@ ibexa.rest.trash.restore_trash_item:
ibexa.rest.load_trash_items:
path: /content/trash
- controller: Ibexa\Rest\Server\Controller\Trash::loadTrashItems
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashItemListController::loadTrashItems
methods: [GET]
ibexa.rest.empty_trash:
path: /content/trash
- controller: Ibexa\Rest\Server\Controller\Trash::emptyTrash
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashEmptyController::emptyTrash
methods: [DELETE]
ibexa.rest.load_trash_item:
path: /content/trash/{trashItemId}
- controller: Ibexa\Rest\Server\Controller\Trash::loadTrashItem
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashItemLoadByIdController::loadTrashItem
methods: [GET]
requirements:
trashItemId: \d+
ibexa.rest.delete_trash_item:
path: /content/trash/{trashItemId}
- controller: Ibexa\Rest\Server\Controller\Trash::deleteTrashItem
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashItemDeleteController::deleteTrashItem
methods: [DELETE]
requirements:
trashItemId: \d+
ibexa.rest.restore_trash_item:
path: /content/trash/{trashItemId}
- controller: Ibexa\Rest\Server\Controller\Trash::restoreTrashItem
+ controller: Ibexa\Rest\Server\Controller\Trash\TrashItemRestoreController::restoreTrashItem
methods: [MOVE]
requirements:
trashItemId: \d+
@@ -761,24 +761,24 @@ ibexa.rest.restore_trash_item:
ibexa.rest.list_url_wildcards:
path: /content/urlwildcards
- controller: Ibexa\Rest\Server\Controller\URLWildcard::listURLWildcards
+ controller: Ibexa\Rest\Server\Controller\URLWildcard\URLWildcardListController::listURLWildcards
methods: [GET]
ibexa.rest.create_url_wildcard:
path: /content/urlwildcards
- controller: Ibexa\Rest\Server\Controller\URLWildcard::createURLWildcard
+ controller: Ibexa\Rest\Server\Controller\URLWildcard\URLWildcardCreateController::createURLWildcard
methods: [POST]
ibexa.rest.load_url_wildcard:
path: /content/urlwildcards/{urlWildcardId}
- controller: Ibexa\Rest\Server\Controller\URLWildcard::loadURLWildcard
+ controller: Ibexa\Rest\Server\Controller\URLWildcard\URLWildcardLoadByIdController::loadURLWildcard
methods: [GET]
requirements:
urlWildcardId: \d+
ibexa.rest.delete_url_wildcard:
path: /content/urlwildcards/{urlWildcardId}
- controller: Ibexa\Rest\Server\Controller\URLWildcard::deleteURLWildcard
+ controller: Ibexa\Rest\Server\Controller\URLWildcard\URLWildcardDeleteController::deleteURLWildcard
methods: [DELETE]
requirements:
urlWildcardId: \d+
@@ -794,7 +794,7 @@ ibexa.rest.list_policies_for_user:
ibexa.rest.role.publish:
path: /user/roles/{roleId}/draft
- controller: Ibexa\Rest\Server\Controller\Role::publishRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftPublishController::publishRoleDraft
condition: 'ibexa_get_media_type(request) === "PublishRoleInput"'
methods: [POST]
options:
@@ -804,95 +804,95 @@ ibexa.rest.role.publish:
ibexa.rest.list_roles:
path: /user/roles
- controller: Ibexa\Rest\Server\Controller\Role::listRoles
+ controller: Ibexa\Rest\Server\Controller\Role\RoleListController::listRoles
methods: [GET]
ibexa.rest.create_role:
path: /user/roles
- controller: Ibexa\Rest\Server\Controller\Role::createRole
+ controller: Ibexa\Rest\Server\Controller\Role\RoleCreateController::createRole
methods: [POST]
requirements:
ibexa.rest.create_role_draft:
path: /user/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::createRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftCreateController::createRoleDraft
methods: [POST]
requirements:
roleId: \d+
ibexa.rest.load_role:
path: /user/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::loadRole
+ controller: Ibexa\Rest\Server\Controller\Role\RoleLoadByIdController::loadRole
methods: [GET]
requirements:
roleId: \d+
ibexa.rest.load_role_draft:
path: /user/roles/{roleId}/draft
- controller: Ibexa\Rest\Server\Controller\Role::loadRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftLoadByRoleIdController::loadRoleDraft
methods: [GET]
requirements:
roleId: \d+
ibexa.rest.update_role:
path: /user/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::updateRole
+ controller: Ibexa\Rest\Server\Controller\Role\RoleUpdateController::updateRole
methods: [PATCH]
requirements:
roleId: \d+
ibexa.rest.update_role_draft:
path: /user/roles/{roleId}/draft
- controller: Ibexa\Rest\Server\Controller\Role::updateRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftUpdateController::updateRoleDraft
methods: [PATCH]
requirements:
roleId: \d+
ibexa.rest.publish_role_draft:
path: /user/roles/{roleId}/draft
- controller: Ibexa\Rest\Server\Controller\Role::publishRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftPublishController::publishRoleDraft
methods: [PUBLISH]
requirements:
roleId: \d+
ibexa.rest.delete_role:
path: /user/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::deleteRole
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDeleteController::deleteRole
methods: [DELETE]
requirements:
roleId: \d+
ibexa.rest.delete_role_draft:
path: /user/roles/{roleId}/draft
- controller: Ibexa\Rest\Server\Controller\Role::deleteRoleDraft
+ controller: Ibexa\Rest\Server\Controller\Role\RoleDraftDeleteController::deleteRoleDraft
methods: [DELETE]
requirements:
roleId: \d+
ibexa.rest.load_policies:
path: /user/roles/{roleId}/policies
- controller: Ibexa\Rest\Server\Controller\Role::loadPolicies
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyListController::loadPolicies
methods: [GET]
requirements:
roleId: \d+
ibexa.rest.add_policy:
path: /user/roles/{roleId}/policies
- controller: Ibexa\Rest\Server\Controller\Role::addPolicy
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyCreateController::addPolicy
methods: [POST]
requirements:
roleId: \d+
ibexa.rest.delete_policies:
path: /user/roles/{roleId}/policies
- controller: Ibexa\Rest\Server\Controller\Role::deletePolicies
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyDeleteAllFromRoleController::deletePolicies
methods: [DELETE]
requirements:
roleId: \d+
ibexa.rest.load_policy:
path: /user/roles/{roleId}/policies/{policyId}
- controller: Ibexa\Rest\Server\Controller\Role::loadPolicy
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyLoadByIdController::loadPolicy
methods: [GET]
requirements:
roleId: \d+
@@ -900,7 +900,7 @@ ibexa.rest.load_policy:
ibexa.rest.update_policy:
path: /user/roles/{roleId}/policies/{policyId}
- controller: Ibexa\Rest\Server\Controller\Role::updatePolicy
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyUpdateController::updatePolicy
methods: [PATCH]
requirements:
roleId: \d+
@@ -908,7 +908,7 @@ ibexa.rest.update_policy:
ibexa.rest.delete_policy:
path: /user/roles/{roleId}/policies/{policyId}
- controller: Ibexa\Rest\Server\Controller\Role::deletePolicy
+ controller: Ibexa\Rest\Server\Controller\Role\RolePolicyDeleteController::deletePolicy
methods: [DELETE]
requirements:
roleId: \d+
@@ -918,7 +918,7 @@ ibexa.rest.delete_policy:
ibexa.rest.user_group.move:
path: /user/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::moveGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupMoveController::moveGroup
condition: 'ibexa_get_media_type(request) === "MoveUserGroupInput"'
methods: [POST]
options:
@@ -928,57 +928,57 @@ ibexa.rest.user_group.move:
ibexa.rest.verify_users:
path: /user/users
- controller: Ibexa\Rest\Server\Controller\User::verifyUsers
+ controller: Ibexa\Rest\Server\Controller\User\UserVerifyController::verifyUsers
methods: [HEAD]
ibexa.rest.load_users:
path: /user/users
- controller: Ibexa\Rest\Server\Controller\User::loadUsers
+ controller: Ibexa\Rest\Server\Controller\User\UserListController::loadUsers
methods: [GET]
ibexa.rest.load_user:
path: /user/users/{userId}
- controller: Ibexa\Rest\Server\Controller\User::loadUser
+ controller: Ibexa\Rest\Server\Controller\User\UserLoadByIdController::loadUser
methods: [GET]
requirements:
userId: \d+
ibexa.rest.current_user:
path: /user/current
- controller: Ibexa\Rest\Server\Controller\User::redirectToCurrentUser
+ controller: Ibexa\Rest\Server\Controller\User\UserRedirectToCurrentUserController::redirectToCurrentUser
methods: [GET]
ibexa.rest.update_user:
path: /user/users/{userId}
- controller: Ibexa\Rest\Server\Controller\User::updateUser
+ controller: Ibexa\Rest\Server\Controller\User\UserUpdateController::updateUser
methods: [PATCH]
requirements:
userId: \d+
ibexa.rest.delete_user:
path: /user/users/{userId}
- controller: Ibexa\Rest\Server\Controller\User::deleteUser
+ controller: Ibexa\Rest\Server\Controller\User\UserDeleteController::deleteUser
methods: [DELETE]
requirements:
userId: \d+
ibexa.rest.load_user_groups_of_user:
path: /user/users/{userId}/groups
- controller: Ibexa\Rest\Server\Controller\User::loadUserGroupsOfUser
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupsOfUserListController::loadUserGroupsOfUser
methods: [GET]
requirements:
userId: \d+
ibexa.rest.assign_user_to_user_group:
path: /user/users/{userId}/groups
- controller: Ibexa\Rest\Server\Controller\User::assignUserToUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserAssignToUserGroupController::assignUserToUserGroup
methods: [POST]
requirements:
userId: \d+
ibexa.rest.unassign_user_from_user_group:
path: /user/users/{userId}/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::unassignUserFromUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserUnassignFromUserGroupController::unassignUserFromUserGroup
methods: [DELETE]
requirements:
userId: \d+
@@ -986,28 +986,28 @@ ibexa.rest.unassign_user_from_user_group:
ibexa.rest.load_user_drafts:
path: /user/users/{userId}/drafts
- controller: Ibexa\Rest\Server\Controller\User::loadUserDrafts
+ controller: Ibexa\Rest\Server\Controller\User\UserDraftListController::loadUserDrafts
methods: [GET]
requirements:
userId: \d+
ibexa.rest.load_role_assignments_for_user:
path: /user/users/{userId}/roles
- controller: Ibexa\Rest\Server\Controller\Role::loadRoleAssignmentsForUser
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignmentForUserListController::loadRoleAssignmentsForUser
methods: [GET]
requirements:
userId: \d+
ibexa.rest.assign_role_to_user:
path: /user/users/{userId}/roles
- controller: Ibexa\Rest\Server\Controller\Role::assignRoleToUser
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignToUserController::assignRoleToUser
methods: [POST]
requirements:
userId: \d+
ibexa.rest.load_role_assignment_for_user:
path: /user/users/{userId}/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::loadRoleAssignmentForUser
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignmentForUserLoadByIdController::loadRoleAssignmentForUser
methods: [GET]
requirements:
userId: \d+
@@ -1015,7 +1015,7 @@ ibexa.rest.load_role_assignment_for_user:
ibexa.rest.unassign_role_from_user:
path: /user/users/{userId}/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::unassignRoleFromUser
+ controller: Ibexa\Rest\Server\Controller\Role\RoleUnassignFromUserController::unassignRoleFromUser
methods: [DELETE]
requirements:
userId: \d+
@@ -1023,92 +1023,92 @@ ibexa.rest.unassign_role_from_user:
ibexa.rest.load_user_groups:
path: /user/groups
- controller: Ibexa\Rest\Server\Controller\User::loadUserGroups
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupListController::loadUserGroups
methods: [GET]
ibexa.rest.load_root_user_group:
path: /user/groups/root
- controller: Ibexa\Rest\Server\Controller\User::loadRootUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupOfRootLoadController::loadRootUserGroup
methods: [GET]
ibexa.rest.create_root_user_group:
path: /user/groups/subgroups
- controller: Ibexa\Rest\Server\Controller\User::createUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupCreateController::createUserGroup
methods: [POST]
ibexa.rest.load_user_group:
path: /user/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::loadUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupLoadByPathController::loadUserGroup
methods: [GET]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.update_user_group:
path: /user/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::updateUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupUpdateController::updateUserGroup
methods: [PATCH]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.delete_user_group:
path: /user/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::deleteUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupDeleteController::deleteUserGroup
methods: [DELETE]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.move_user_group:
path: /user/groups/{groupPath}
- controller: Ibexa\Rest\Server\Controller\User::moveUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupMoveController::moveUserGroup
methods: [MOVE]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.load_sub_user_groups:
path: /user/groups/{groupPath}/subgroups
- controller: Ibexa\Rest\Server\Controller\User::loadSubUserGroups
+ controller: Ibexa\Rest\Server\Controller\User\UserSubGroupListController::loadSubUserGroups
methods: [GET]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.create_user_group:
path: /user/groups/{groupPath}/subgroups
- controller: Ibexa\Rest\Server\Controller\User::createUserGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupCreateController::createUserGroup
methods: [POST]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.load_users_from_group:
path: /user/groups/{groupPath}/users
- controller: Ibexa\Rest\Server\Controller\User::loadUsersFromGroup
+ controller: Ibexa\Rest\Server\Controller\User\UserGroupUsersListController::loadUsersFromGroup
methods: [GET]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.create_user:
path: /user/groups/{groupPath}/users
- controller: Ibexa\Rest\Server\Controller\User::createUser
+ controller: Ibexa\Rest\Server\Controller\User\UserCreateController::createUser
methods: [POST]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.load_role_assignments_for_user_group:
path: /user/groups/{groupPath}/roles
- controller: Ibexa\Rest\Server\Controller\Role::loadRoleAssignmentsForUserGroup
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignmentForUserGroupListController::loadRoleAssignmentsForUserGroup
methods: [GET]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.assign_role_to_user_group:
path: /user/groups/{groupPath}/roles
- controller: Ibexa\Rest\Server\Controller\Role::assignRoleToUserGroup
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignToUserGroupController::assignRoleToUserGroup
methods: [POST]
requirements:
groupPath: "[0-9/]+"
ibexa.rest.load_role_assignment_for_user_group:
path: /user/groups/{groupPath}/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::loadRoleAssignmentForUserGroup
+ controller: Ibexa\Rest\Server\Controller\Role\RoleAssignmentForUserGroupLoadByIdController::loadRoleAssignmentForUserGroup
methods: [GET]
requirements:
groupPath: "[0-9/]+"
@@ -1116,7 +1116,7 @@ ibexa.rest.load_role_assignment_for_user_group:
ibexa.rest.unassign_role_from_user_group:
path: /user/groups/{groupPath}/roles/{roleId}
- controller: Ibexa\Rest\Server\Controller\Role::unassignRoleFromUserGroup
+ controller: Ibexa\Rest\Server\Controller\Role\RoleUnassignFromUserGroupController::unassignRoleFromUserGroup
methods: [DELETE]
requirements:
groupPath: "[0-9/]+"
@@ -1131,7 +1131,7 @@ ibexa.rest.create_session:
ibexa.rest.check_session:
path: /user/sessions/current
- controller: Ibexa\Rest\Server\Controller\SessionController::checkSessionAction
+ controller: Ibexa\Rest\Server\Controller\Session\SessionCheckController::checkSessionAction
methods: [GET]
defaults:
csrf_protection: false
@@ -1147,29 +1147,29 @@ ibexa.rest.delete_session:
ibexa.rest.list_global_url_aliases:
path: /content/urlaliases
- controller: Ibexa\Rest\Server\Controller\URLAlias::listGlobalURLAliases
+ controller: Ibexa\Rest\Server\Controller\URLAlias\URLAliasListGlobalController::listGlobalURLAliases
methods: [GET]
ibexa.rest.list_location_url_aliases:
path: /content/locations/{locationPath}/urlaliases
- controller: Ibexa\Rest\Server\Controller\URLAlias::listLocationURLAliases
+ controller: Ibexa\Rest\Server\Controller\URLAlias\URLAliasListLocationController::listLocationURLAliases
methods: [GET]
requirements:
locationPath: "[0-9/]+"
ibexa.rest.create_url_alias:
path: /content/urlaliases
- controller: Ibexa\Rest\Server\Controller\URLAlias::createURLAlias
+ controller: Ibexa\Rest\Server\Controller\URLAlias\URLAliasCreateController::createURLAlias
methods: [POST]
ibexa.rest.load_url_alias:
path: /content/urlaliases/{urlAliasId}
- controller: Ibexa\Rest\Server\Controller\URLAlias::loadURLAlias
+ controller: Ibexa\Rest\Server\Controller\URLAlias\URLAliasLoadByIdController::loadURLAlias
methods: [GET]
ibexa.rest.delete_url_alias:
path: /content/urlaliases/{urlAliasId}
- controller: Ibexa\Rest\Server\Controller\URLAlias::deleteURLAlias
+ controller: Ibexa\Rest\Server\Controller\URLAlias\URLAliasDeleteController::deleteURLAlias
methods: [DELETE]
# Services
@@ -1183,28 +1183,28 @@ ibexa.rest.load_country_list:
ibexa.rest.create_bookmark:
path: /bookmark/{locationId}
- controller: Ibexa\Rest\Server\Controller\Bookmark::createBookmark
+ controller: Ibexa\Rest\Server\Controller\Bookmark\BookmarkCreateController::createBookmark
methods: [POST]
requirements:
locationId: "[0-9]+"
ibexa.rest.delete_bookmark:
path: /bookmark/{locationId}
- controller: Ibexa\Rest\Server\Controller\Bookmark::deleteBookmark
+ controller: Ibexa\Rest\Server\Controller\Bookmark\BookmarkDeleteController::deleteBookmark
methods: [DELETE]
requirements:
locationId: "[0-9]+"
ibexa.rest.is_bookmarked:
path: /bookmark/{locationId}
- controller: Ibexa\Rest\Server\Controller\Bookmark::isBookmarked
+ controller: Ibexa\Rest\Server\Controller\Bookmark\BookmarkIsBookmarkedController::isBookmarked
methods: [GET, HEAD]
requirements:
locationId: "[0-9]+"
ibexa.rest.load_bookmarks:
path: /bookmark
- controller: Ibexa\Rest\Server\Controller\Bookmark::loadBookmarks
+ controller: Ibexa\Rest\Server\Controller\Bookmark\BookmarkListController::loadBookmarks
methods: [GET]
# JWT
diff --git a/src/bundle/Resources/config/services.yml b/src/bundle/Resources/config/services.yml
index ed5a3633b..221689776 100644
--- a/src/bundle/Resources/config/services.yml
+++ b/src/bundle/Resources/config/services.yml
@@ -79,11 +79,12 @@ services:
arguments: ['@Ibexa\Rest\Server\Service\ExpressionRouterRootResourceBuilder']
tags: [controller.service_arguments]
- Ibexa\Rest\Server\Controller\Section:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.section'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Section\:
+ resource: '../../../lib/Server/Controller/Section'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
Ibexa\Rest\Server\Controller\BinaryContent:
parent: Ibexa\Rest\Server\Controller
@@ -92,76 +93,75 @@ services:
- '@ibexa.config.resolver'
tags: [controller.service_arguments]
- Ibexa\Rest\Server\Controller\Content:
- parent: Ibexa\Rest\Server\Controller
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Content\:
+ resource: '../../../lib/Server/Controller/Content'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\ContentType:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.content_type'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\ContentType\:
+ resource: '../../../lib/Server/Controller/ContentType'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\Role:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.role'
- - '@ibexa.api.service.user'
- - '@ibexa.api.service.location'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Role\:
+ resource: '../../../lib/Server/Controller/Role'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\Language:
+ Ibexa\Rest\Server\Controller\Language\:
+ resource: '../../../lib/Server/Controller/Language'
autowire: true
- tags: [controller.service_arguments, ibexa.api_platform.resource]
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\Location:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.location'
- - '@ibexa.api.service.content'
- - '@ibexa.api.service.trash'
- - '@ibexa.api.service.url_alias'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Location\:
+ resource: '../../../lib/Server/Controller/Location'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\ObjectState:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.object_state'
- - '@ibexa.api.service.content'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\ObjectState\:
+ resource: '../../../lib/Server/Controller/ObjectState'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\Trash:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.trash'
- - '@ibexa.api.service.location'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Trash\:
+ resource: '../../../lib/Server/Controller/Trash'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\User:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.user'
- - '@ibexa.api.service.role'
- - '@ibexa.api.service.content'
- - '@ibexa.api.service.content_type'
- - '@ibexa.api.service.location'
- - '@ibexa.api.service.section'
- - '@ibexa.api.repository'
- - '@Ibexa\Contracts\Core\Repository\PermissionResolver'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\User\:
+ resource: '../../../lib/Server/Controller/User'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\URLWildcard:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.url_wildcard'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\URLWildcard\:
+ resource: '../../../lib/Server/Controller/URLWildcard'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
- Ibexa\Rest\Server\Controller\URLAlias:
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.url_alias'
- - '@ibexa.api.service.location'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\URLAlias\:
+ resource: '../../../lib/Server/Controller/URLAlias'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
Ibexa\Rest\Server\Controller\Views:
parent: Ibexa\Rest\Server\Controller
@@ -169,9 +169,10 @@ services:
- '@ibexa.api.service.search'
tags: [controller.service_arguments]
- Ibexa\Rest\Server\Controller\SessionController:
- class: Ibexa\Rest\Server\Controller\SessionController
- parent: Ibexa\Rest\Server\Controller
+ Ibexa\Rest\Server\Controller\Session\:
+ resource: '../../../lib/Server/Controller/Session'
+ autowire: true
+ autoconfigure: true
arguments:
$permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver'
$userService: '@Ibexa\Contracts\Core\Repository\UserService'
@@ -181,13 +182,12 @@ services:
$configResolver: '@Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface'
tags: [controller.service_arguments]
- Ibexa\Rest\Server\Controller\Bookmark:
- class: Ibexa\Rest\Server\Controller\Bookmark
- parent: Ibexa\Rest\Server\Controller
- arguments:
- - '@ibexa.api.service.bookmark'
- - '@ibexa.api.service.location'
- tags: [controller.service_arguments]
+ Ibexa\Rest\Server\Controller\Bookmark\:
+ resource: '../../../lib/Server/Controller/Bookmark'
+ autowire: true
+ autoconfigure: true
+ tags:
+ - controller.service_arguments
Ibexa\Rest\Server\Controller\JWT:
autowire: true
diff --git a/src/lib/Server/Controller/Bookmark.php b/src/lib/Server/Controller/Bookmark.php
deleted file mode 100644
index 377067a3e..000000000
--- a/src/lib/Server/Controller/Bookmark.php
+++ /dev/null
@@ -1,160 +0,0 @@
-bookmarkService = $bookmarkService;
- $this->locationService = $locationService;
- }
-
- /**
- * Add given location to bookmarks.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- * @param int $locationId
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- *
- * @return \Ibexa\Rest\Value
- */
- public function createBookmark(Request $request, int $locationId): RestValue
- {
- $location = $this->locationService->loadLocation($locationId);
-
- try {
- $this->bookmarkService->createBookmark($location);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.is_bookmarked',
- [
- 'locationId' => $locationId,
- ]
- )
- );
- } catch (InvalidArgumentException $e) {
- return new Values\Conflict();
- }
- }
-
- /**
- * Deletes a given bookmark.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- * @param int $locationId
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- *
- * @return \Ibexa\Rest\Value
- */
- public function deleteBookmark(Request $request, int $locationId): RestValue
- {
- $location = $this->locationService->loadLocation($locationId);
-
- try {
- $this->bookmarkService->deleteBookmark($location);
-
- return new Values\NoContent();
- } catch (InvalidArgumentException $e) {
- throw new Exceptions\NotFoundException("Location {$locationId} is not bookmarked");
- }
- }
-
- /**
- * Checks if given location is bookmarked.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- * @param int $locationId
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- *
- * @return \Ibexa\Rest\Server\Values\OK
- */
- public function isBookmarked(Request $request, int $locationId): Values\OK
- {
- $location = $this->locationService->loadLocation($locationId);
-
- if (!$this->bookmarkService->isBookmarked($location)) {
- throw new Exceptions\NotFoundException("Location {$locationId} is not bookmarked");
- }
-
- return new Values\OK();
- }
-
- /**
- * List bookmarked locations.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- *
- * @return \Ibexa\Rest\Value
- */
- public function loadBookmarks(Request $request): RestValue
- {
- $offset = $request->query->getInt('offset', 0);
- $limit = $request->query->getInt('limit', 25);
-
- $restLocations = [];
- $bookmarks = $this->bookmarkService->loadBookmarks($offset, $limit);
- foreach ($bookmarks as $bookmark) {
- $restLocations[] = new Values\RestLocation(
- $bookmark,
- $this->locationService->getLocationChildCount($bookmark)
- );
- }
-
- return new Values\BookmarkList($bookmarks->totalCount, $restLocations);
- }
-
- /**
- * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
- *
- * @param string $path
- *
- * @return mixed
- */
- private function extractLocationIdFromPath(string $path)
- {
- $pathParts = explode('/', $path);
-
- return array_pop($pathParts);
- }
-}
diff --git a/src/lib/Server/Controller/Bookmark/BookmarkCreateController.php b/src/lib/Server/Controller/Bookmark/BookmarkCreateController.php
new file mode 100644
index 000000000..eb8d089db
--- /dev/null
+++ b/src/lib/Server/Controller/Bookmark/BookmarkCreateController.php
@@ -0,0 +1,115 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Add given Location to bookmarks of the current user.',
+ tags: [
+ 'Bookmark',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'locationId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Created.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to given Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the given Location does not exist.',
+ ],
+ Response::HTTP_CONFLICT => [
+ 'description' => 'Error - Location is already bookmarked.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class BookmarkCreateController extends RestController
+{
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\BookmarkService
+ */
+ protected $bookmarkService;
+
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\LocationService
+ */
+ protected $locationService;
+
+ /**
+ * Bookmark constructor.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\BookmarkService $bookmarkService
+ * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
+ */
+ public function __construct(BookmarkService $bookmarkService, LocationService $locationService)
+ {
+ $this->bookmarkService = $bookmarkService;
+ $this->locationService = $locationService;
+ }
+
+ /**
+ * Add given location to bookmarks.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * @param int $locationId
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ *
+ * @return \Ibexa\Rest\Value
+ */
+ public function createBookmark(Request $request, int $locationId): RestValue
+ {
+ $location = $this->locationService->loadLocation($locationId);
+
+ try {
+ $this->bookmarkService->createBookmark($location);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.is_bookmarked',
+ [
+ 'locationId' => $locationId,
+ ]
+ )
+ );
+ } catch (InvalidArgumentException $e) {
+ return new Values\Conflict();
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/Bookmark/BookmarkDeleteController.php b/src/lib/Server/Controller/Bookmark/BookmarkDeleteController.php
new file mode 100644
index 000000000..527c8a0d6
--- /dev/null
+++ b/src/lib/Server/Controller/Bookmark/BookmarkDeleteController.php
@@ -0,0 +1,101 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'Deleted - no content.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized for the given Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the given Location does not exist / is not bookmarked.',
+ ],
+ ],
+ ),
+)]
+class BookmarkDeleteController extends RestController
+{
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\BookmarkService
+ */
+ protected $bookmarkService;
+
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\LocationService
+ */
+ protected $locationService;
+
+ /**
+ * Bookmark constructor.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\BookmarkService $bookmarkService
+ * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
+ */
+ public function __construct(BookmarkService $bookmarkService, LocationService $locationService)
+ {
+ $this->bookmarkService = $bookmarkService;
+ $this->locationService = $locationService;
+ }
+
+ /**
+ * Deletes a given bookmark.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * @param int $locationId
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ *
+ * @return \Ibexa\Rest\Value
+ */
+ public function deleteBookmark(Request $request, int $locationId): RestValue
+ {
+ $location = $this->locationService->loadLocation($locationId);
+
+ try {
+ $this->bookmarkService->deleteBookmark($location);
+
+ return new Values\NoContent();
+ } catch (InvalidArgumentException $e) {
+ throw new Exceptions\NotFoundException("Location {$locationId} is not bookmarked");
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/Bookmark/BookmarkIsBookmarkedController.php b/src/lib/Server/Controller/Bookmark/BookmarkIsBookmarkedController.php
new file mode 100644
index 000000000..8414073ec
--- /dev/null
+++ b/src/lib/Server/Controller/Bookmark/BookmarkIsBookmarkedController.php
@@ -0,0 +1,97 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - bookmarked.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized for the given Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the given Location does not exist / is not bookmarked.',
+ ],
+ ],
+ ),
+)]
+class BookmarkIsBookmarkedController extends RestController
+{
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\BookmarkService
+ */
+ protected $bookmarkService;
+
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\LocationService
+ */
+ protected $locationService;
+
+ /**
+ * Bookmark constructor.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\BookmarkService $bookmarkService
+ * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
+ */
+ public function __construct(BookmarkService $bookmarkService, LocationService $locationService)
+ {
+ $this->bookmarkService = $bookmarkService;
+ $this->locationService = $locationService;
+ }
+
+ /**
+ * Checks if given location is bookmarked.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * @param int $locationId
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ *
+ * @return \Ibexa\Rest\Server\Values\OK
+ */
+ public function isBookmarked(Request $request, int $locationId): Values\OK
+ {
+ $location = $this->locationService->loadLocation($locationId);
+
+ if (!$this->bookmarkService->isBookmarked($location)) {
+ throw new Exceptions\NotFoundException("Location {$locationId} is not bookmarked");
+ }
+
+ return new Values\OK();
+ }
+}
diff --git a/src/lib/Server/Controller/Bookmark/BookmarkListController.php b/src/lib/Server/Controller/Bookmark/BookmarkListController.php
new file mode 100644
index 000000000..5f916ffc0
--- /dev/null
+++ b/src/lib/Server/Controller/Bookmark/BookmarkListController.php
@@ -0,0 +1,112 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.BookmarkList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/BookmarkList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.BookmarkList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/BookmarkListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/bookmark/GET/BookmarkList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to list bookmarks.',
+ ],
+ ],
+ ),
+)]
+class BookmarkListController extends RestController
+{
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\BookmarkService
+ */
+ protected $bookmarkService;
+
+ /**
+ * @var \Ibexa\Contracts\Core\Repository\LocationService
+ */
+ protected $locationService;
+
+ /**
+ * Bookmark constructor.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\BookmarkService $bookmarkService
+ * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
+ */
+ public function __construct(BookmarkService $bookmarkService, LocationService $locationService)
+ {
+ $this->bookmarkService = $bookmarkService;
+ $this->locationService = $locationService;
+ }
+
+ /**
+ * List bookmarked locations.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
+ *
+ * @return \Ibexa\Rest\Value
+ */
+ public function loadBookmarks(Request $request): RestValue
+ {
+ $offset = $request->query->getInt('offset', 0);
+ $limit = $request->query->getInt('limit', 25);
+
+ $restLocations = [];
+ $bookmarks = $this->bookmarkService->loadBookmarks($offset, $limit);
+ foreach ($bookmarks as $bookmark) {
+ $restLocations[] = new Values\RestLocation(
+ $bookmark,
+ $this->locationService->getLocationChildCount($bookmark)
+ );
+ }
+
+ return new Values\BookmarkList($bookmarks->totalCount, $restLocations);
+ }
+}
diff --git a/src/lib/Server/Controller/Content.php b/src/lib/Server/Controller/Content.php
deleted file mode 100644
index 43cf31270..000000000
--- a/src/lib/Server/Controller/Content.php
+++ /dev/null
@@ -1,897 +0,0 @@
-query->has('remoteId')) {
- throw new BadRequestException("'remoteId' parameter is required.");
- }
-
- $contentInfo = $this->repository->getContentService()->loadContentInfoByRemoteId(
- (string)$request->query->get('remoteId')
- );
-
- return new Values\TemporaryRedirect(
- $this->router->generate(
- 'ibexa.rest.load_content',
- [
- 'contentId' => $contentInfo->id,
- ]
- )
- );
- }
-
- /**
- * Loads a content info, potentially with the current version embedded.
- *
- * @param mixed $contentId
- * @param \Symfony\Component\HttpFoundation\Request $request
- *
- * @return \Ibexa\Rest\Server\Values\RestContent
- */
- public function loadContent($contentId, Request $request)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- $mainLocation = null;
- if (!empty($contentInfo->mainLocationId)) {
- $mainLocation = $this->repository->getLocationService()->loadLocation($contentInfo->mainLocationId);
- }
-
- $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
-
- $contentVersion = null;
- $relations = null;
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.content') {
- $languages = $this->getLanguages($request);
-
- $contentVersion = $this->repository->getContentService()->loadContent($contentId, $languages);
- $relations = $this->relationListFacade->getRelations($contentVersion->getVersionInfo());
- }
-
- $restContent = new Values\RestContent(
- $contentInfo,
- $mainLocation,
- $contentVersion,
- $contentType,
- $relations !== null ? iterator_to_array($relations) : null,
- $request->getPathInfo()
- );
-
- if ($contentInfo->mainLocationId === null) {
- return $restContent;
- }
-
- return new Values\CachedValue(
- $restContent,
- ['locationId' => $contentInfo->mainLocationId]
- );
- }
-
- /**
- * Updates a content's metadata.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\RestContent
- */
- public function updateContentMetadata($contentId, Request $request)
- {
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- // update section
- if ($updateStruct->sectionId !== null) {
- $section = $this->repository->getSectionService()->loadSection($updateStruct->sectionId);
- $this->repository->getSectionService()->assignSection($contentInfo, $section);
- $updateStruct->sectionId = null;
- }
-
- // @todo Consider refactoring! ContentService::updateContentMetadata throws the same exception
- // in case the updateStruct is empty and if remoteId already exists. Since REST version of update struct
- // includes section ID in addition to other fields, we cannot throw exception if only sectionId property
- // is set, so we must skip updating content in that case instead of allowing propagation of the exception.
- foreach ($updateStruct as $propertyName => $propertyValue) {
- if ($propertyName !== 'sectionId' && $propertyValue !== null) {
- // update content
- $this->repository->getContentService()->updateContentMetadata($contentInfo, $updateStruct);
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- break;
- }
- }
-
- try {
- $locationInfo = null !== $contentInfo->mainLocationId
- ? $this->repository->getLocationService()->loadLocation($contentInfo->mainLocationId)
- : null;
- } catch (NotFoundException $e) {
- $locationInfo = null;
- }
-
- return new Values\RestContent(
- $contentInfo,
- $locationInfo
- );
- }
-
- /**
- * Loads a specific version of a given content object.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
- */
- public function redirectCurrentVersion($contentId)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- return new Values\TemporaryRedirect(
- $this->router->generate(
- 'ibexa.rest.load_content_in_version',
- [
- 'contentId' => $contentId,
- 'versionNumber' => $contentInfo->currentVersionNo,
- ]
- )
- );
- }
-
- /**
- * Loads a specific version of a given content object.
- *
- * @param mixed $contentId
- * @param int $versionNumber
- *
- * @return \Ibexa\Rest\Server\Values\Version
- */
- public function loadContentInVersion($contentId, $versionNumber, Request $request)
- {
- $languages = $this->getLanguages($request);
-
- $content = $this->repository->getContentService()->loadContent(
- $contentId,
- $languages,
- $versionNumber
- );
- $contentType = $this->repository->getContentTypeService()->loadContentType(
- $content->getVersionInfo()->getContentInfo()->contentTypeId
- );
-
- $versionValue = new Values\Version(
- $content,
- $contentType,
- iterator_to_array($this->relationListFacade->getRelations($content->getVersionInfo())),
- $request->getPathInfo()
- );
-
- if ($content->contentInfo->mainLocationId === null || $content->versionInfo->status === VersionInfo::STATUS_DRAFT) {
- return $versionValue;
- }
-
- return new Values\CachedValue(
- $versionValue,
- ['locationId' => $content->contentInfo->mainLocationId]
- );
- }
-
- /**
- * Creates a new content draft assigned to the authenticated user.
- * If a different userId is given in the input it is assigned to the
- * given user but this required special rights for the authenticated
- * user (this is useful for content staging where the transfer process
- * does not have to authenticate with the user which created the content
- * object in the source server). The user has to publish the content if
- * it should be visible.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- *
- * @return \Ibexa\Rest\Server\Values\CreatedContent
- */
- public function createContent(Request $request)
- {
- $contentCreate = $this->parseContentRequest($request);
-
- return $this->doCreateContent($request, $contentCreate);
- }
-
- /**
- * The content is deleted. If the content has locations (which is required in 4.x)
- * on delete all locations assigned the content object are deleted via delete subtree.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteContent($contentId)
- {
- $this->repository->getContentService()->deleteContent(
- $this->repository->getContentService()->loadContentInfo($contentId)
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Creates a new content object as copy under the given parent location given in the destination header.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\ResourceCreated
- */
- public function copyContent($contentId, Request $request)
- {
- /** @var string $destination */
- $destination = $request->headers->get('Destination');
-
- $parentLocationParts = explode('/', $destination);
- $copiedContent = $this->repository->getContentService()->copyContent(
- $this->repository->getContentService()->loadContentInfo($contentId),
- $this->repository->getLocationService()->newLocationCreateStruct(array_pop($parentLocationParts))
- );
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_content',
- ['contentId' => $copiedContent->id]
- )
- );
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- */
- public function copy(int $contentId, Request $request): Values\ResourceCreated
- {
- $contentService = $this->repository->getContentService();
- $locationService = $this->repository->getLocationService();
-
- $contentInfo = $contentService->loadContentInfo($contentId);
-
- /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $destinationLocation */
- $destinationLocation = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent(),
- ),
- );
-
- $copiedContent = $contentService->copyContent(
- $contentInfo,
- $locationService->newLocationCreateStruct($destinationLocation->getId()),
- );
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_content',
- ['contentId' => $copiedContent->id],
- )
- );
- }
-
- /**
- * Deletes a translation from all the Versions of the given Content Object.
- *
- * If any non-published Version contains only the Translation to be deleted, that entire Version will be deleted
- *
- * @param int $contentId
- * @param string $languageCode
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- *
- * @throws \Exception
- */
- public function deleteContentTranslation($contentId, $languageCode)
- {
- $contentService = $this->repository->getContentService();
-
- $this->repository->beginTransaction();
- try {
- $contentInfo = $contentService->loadContentInfo($contentId);
- $contentService->deleteTranslation(
- $contentInfo,
- $languageCode
- );
-
- $this->repository->commit();
-
- return new Values\NoContent();
- } catch (Exception $e) {
- $this->repository->rollback();
- throw $e;
- }
- }
-
- /**
- * Returns a list of all versions of the content. This method does not
- * include fields and relations in the Version elements of the response.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function loadContentVersions(int $contentId, Request $request): Values\VersionList
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- return new Values\VersionList(
- iterator_to_array($this->repository->getContentService()->loadVersions($contentInfo)),
- $request->getPathInfo()
- );
- }
-
- /**
- * The version is deleted.
- *
- * @param mixed $contentId
- * @param mixed $versionNumber
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteContentVersion($contentId, $versionNumber)
- {
- $versionInfo = $this->repository->getContentService()->loadVersionInfo(
- $this->repository->getContentService()->loadContentInfo($contentId),
- $versionNumber
- );
-
- if ($versionInfo->isPublished()) {
- throw new ForbiddenException('Versions with PUBLISHED status cannot be deleted');
- }
-
- $this->repository->getContentService()->deleteVersion(
- $versionInfo
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Remove the given Translation from the given Version Draft.
- *
- * @param int $contentId
- * @param int $versionNumber
- * @param string $languageCode
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- */
- public function deleteTranslationFromDraft($contentId, $versionNumber, $languageCode)
- {
- $contentService = $this->repository->getContentService();
- $versionInfo = $contentService->loadVersionInfoById($contentId, $versionNumber);
-
- if (!$versionInfo->isDraft()) {
- throw new ForbiddenException('Translation can be deleted from a DRAFT version only');
- }
-
- $contentService->deleteTranslationFromDraft($versionInfo, $languageCode);
-
- return new Values\NoContent();
- }
-
- /**
- * The system creates a new draft version as a copy from the given version.
- *
- * @param mixed $contentId
- * @param mixed $versionNumber
- *
- * @return \Ibexa\Rest\Server\Values\CreatedVersion
- */
- public function createDraftFromVersion($contentId, $versionNumber)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
- $contentDraft = $this->repository->getContentService()->createContentDraft(
- $contentInfo,
- $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber)
- );
-
- return new Values\CreatedVersion(
- [
- 'version' => new Values\Version(
- $contentDraft,
- $contentType,
- iterator_to_array($this->relationListFacade->getRelations($contentDraft->getVersionInfo()))
- ),
- ]
- );
- }
-
- /**
- * The system creates a new draft version as a copy from the current version.
- *
- * @param mixed $contentId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if the current version is already a draft
- *
- * @return \Ibexa\Rest\Server\Values\CreatedVersion
- */
- public function createDraftFromCurrentVersion($contentId)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
- $versionInfo = $this->repository->getContentService()->loadVersionInfo(
- $contentInfo
- );
-
- if ($versionInfo->isDraft()) {
- throw new ForbiddenException('Current version already has DRAFT status');
- }
-
- $contentDraft = $this->repository->getContentService()->createContentDraft($contentInfo);
-
- return new Values\CreatedVersion(
- [
- 'version' => new Values\Version(
- $contentDraft,
- $contentType,
- iterator_to_array($this->relationListFacade->getRelations($contentDraft->getVersionInfo()))
- ),
- ]
- );
- }
-
- /**
- * A specific draft is updated.
- *
- * @param mixed $contentId
- * @param mixed $versionNumber
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
- *
- * @return \Ibexa\Rest\Server\Values\Version
- */
- public function updateVersion($contentId, $versionNumber, Request $request)
- {
- $contentUpdateStruct = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- 'Url' => $this->router->generate(
- 'ibexa.rest.update_version',
- [
- 'contentId' => $contentId,
- 'versionNumber' => $versionNumber,
- ]
- ),
- ],
- $request->getContent()
- )
- );
-
- $versionInfo = $this->repository->getContentService()->loadVersionInfo(
- $this->repository->getContentService()->loadContentInfo($contentId),
- $versionNumber
- );
-
- if (!$versionInfo->isDraft()) {
- throw new ForbiddenException('Only versions with DRAFT status can be updated');
- }
-
- try {
- $this->repository->getContentService()->updateContent($versionInfo, $contentUpdateStruct);
- } catch (ContentValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (ContentFieldValidationException $e) {
- throw new RESTContentFieldValidationException($e);
- }
-
- $languages = $this->getLanguages($request);
-
- // Reload the content to handle languages GET parameter
- $content = $this->repository->getContentService()->loadContent(
- $contentId,
- $languages,
- $versionInfo->versionNo
- );
- $contentType = $this->repository->getContentTypeService()->loadContentType(
- $content->getVersionInfo()->getContentInfo()->contentTypeId
- );
-
- return new Values\Version(
- $content,
- $contentType,
- iterator_to_array($this->relationListFacade->getRelations($content->getVersionInfo())),
- $request->getPathInfo()
- );
- }
-
- /**
- * The content version is published.
- *
- * @param mixed $contentId
- * @param mixed $versionNumber
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if version $versionNumber isn't a draft
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function publishVersion($contentId, $versionNumber)
- {
- $versionInfo = $this->repository->getContentService()->loadVersionInfo(
- $this->repository->getContentService()->loadContentInfo($contentId),
- $versionNumber
- );
-
- if (!$versionInfo->isDraft()) {
- throw new ForbiddenException('Only versions with DRAFT status can be published');
- }
-
- $this->repository->getContentService()->publishVersion(
- $versionInfo
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Redirects to the relations of the current version.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
- */
- public function redirectCurrentVersionRelations($contentId)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- return new Values\TemporaryRedirect(
- $this->router->generate(
- 'ibexa.rest.redirect_current_version_relations',
- [
- 'contentId' => $contentId,
- 'versionNumber' => $contentInfo->currentVersionNo,
- ]
- )
- );
- }
-
- /**
- * Loads the relations of the given version.
- *
- * @param mixed $contentId
- * @param mixed $versionNumber
- *
- * @return \Ibexa\Rest\Server\Values\RelationList
- */
- public function loadVersionRelations($contentId, $versionNumber, Request $request)
- {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
-
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- $relationList = $this->contentService->loadRelationList(
- $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber),
- $offset,
- $limit,
- );
-
- $relations = [];
- foreach ($relationList as $relationListItem) {
- if ($relationListItem->hasRelation()) {
- /** @var \Ibexa\Core\Repository\Values\Content\Relation $relation */
- $relation = $relationListItem->getRelation();
- $relations[] = $relation;
- }
- }
-
- $relationListValue = new Values\RelationList(
- $relations,
- $contentId,
- $versionNumber,
- $request->getPathInfo()
- );
-
- if ($contentInfo->mainLocationId === null) {
- return $relationListValue;
- }
-
- return new Values\CachedValue(
- $relationListValue,
- ['locationId' => $contentInfo->mainLocationId]
- );
- }
-
- /**
- * Loads a relation for the given content object and version.
- *
- * @param mixed $contentId
- * @param int $versionNumber
- * @param mixed $relationId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\RestRelation
- */
- public function loadVersionRelation($contentId, $versionNumber, $relationId, Request $request)
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- $relationList = $this->relationListFacade->getRelations(
- $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber)
- );
-
- foreach ($relationList as $relation) {
- if ($relation->id == $relationId) {
- $relation = new Values\RestRelation($relation, $contentId, $versionNumber);
-
- if ($contentInfo->mainLocationId === null) {
- return $relation;
- }
-
- return new Values\CachedValue(
- $relation,
- ['locationId' => $contentInfo->mainLocationId]
- );
- }
- }
-
- throw new Exceptions\NotFoundException("Relation not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Deletes a relation of the given draft.
- *
- * @param mixed $contentId
- * @param int $versionNumber
- * @param mixed $relationId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function removeRelation($contentId, $versionNumber, $relationId, Request $request)
- {
- $versionInfo = $this->repository->getContentService()->loadVersionInfo(
- $this->repository->getContentService()->loadContentInfo($contentId),
- $versionNumber
- );
-
- $versionRelations = $this->relationListFacade->getRelations($versionInfo);
- foreach ($versionRelations as $relation) {
- if ($relation->id == $relationId) {
- if ($relation->type !== Relation::COMMON) {
- throw new ForbiddenException('Relation is not of type COMMON');
- }
-
- if (!$versionInfo->isDraft()) {
- throw new ForbiddenException('Relation of type COMMON can only be removed from drafts');
- }
-
- $this->repository->getContentService()->deleteRelation($versionInfo, $relation->getDestinationContentInfo());
-
- return new Values\NoContent();
- }
- }
-
- throw new Exceptions\NotFoundException("Could not find Relation '{$request->getPathInfo()}'.");
- }
-
- /**
- * Creates a new relation of type COMMON for the given draft.
- *
- * @param mixed $contentId
- * @param int $versionNumber
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if version $versionNumber isn't a draft
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if a relation to the same content already exists
- *
- * @return \Ibexa\Rest\Server\Values\CreatedRelation
- */
- public function createRelation($contentId, $versionNumber, Request $request)
- {
- $destinationContentId = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
- $versionInfo = $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber);
- if (!$versionInfo->isDraft()) {
- throw new ForbiddenException('Relation of type COMMON can only be added to drafts');
- }
-
- try {
- $destinationContentInfo = $this->repository->getContentService()->loadContentInfo($destinationContentId);
- } catch (NotFoundException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- $existingRelations = $this->relationListFacade->getRelations($versionInfo);
- foreach ($existingRelations as $existingRelation) {
- if ($existingRelation->getDestinationContentInfo()->id == $destinationContentId) {
- throw new ForbiddenException('Relation of type COMMON to the selected destination content ID already exists');
- }
- }
-
- $relation = $this->repository->getContentService()->addRelation($versionInfo, $destinationContentInfo);
-
- return new Values\CreatedRelation(
- [
- 'relation' => new Values\RestRelation($relation, $contentId, $versionNumber),
- ]
- );
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function hideContent(int $contentId): Values\NoContent
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- $this->repository->getContentService()->hideContent($contentInfo);
-
- return new Values\NoContent();
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function revealContent(int $contentId): Values\NoContent
- {
- $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
-
- $this->repository->getContentService()->revealContent($contentInfo);
-
- return new Values\NoContent();
- }
-
- /**
- * @throws \Exception
- */
- protected function forward(string $controller): Response
- {
- $path['_controller'] = $controller;
- $request = $this->requestStack->getCurrentRequest();
- if ($request === null) {
- throw new LogicException('No requests in the stack');
- }
- $subRequest = $request->duplicate(null, null, $path);
-
- return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
- }
-
- /**
- * @param \Symfony\Component\HttpFoundation\Request $request
- *
- * @return mixed
- */
- protected function parseContentRequest(Request $request)
- {
- return $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type'), 'Url' => $request->getPathInfo()],
- $request->getContent()
- )
- );
- }
-
- /**
- * @param \Symfony\Component\HttpFoundation\Request $request
- * @param \Ibexa\Rest\Server\Values\RestContentCreateStruct $contentCreate
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedContent
- */
- protected function doCreateContent(Request $request, RestContentCreateStruct $contentCreate)
- {
- try {
- $contentCreateStruct = $contentCreate->contentCreateStruct;
- $contentCreate->locationCreateStruct->sortField = $contentCreateStruct->contentType->defaultSortField;
- $contentCreate->locationCreateStruct->sortOrder = $contentCreateStruct->contentType->defaultSortOrder;
-
- $content = $this->repository->getContentService()->createContent(
- $contentCreateStruct,
- [$contentCreate->locationCreateStruct]
- );
- } catch (ContentValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (ContentFieldValidationException $e) {
- throw new RESTContentFieldValidationException($e);
- }
-
- $contentValue = null;
- $contentType = null;
- $relations = null;
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.content') {
- $contentValue = $content;
- $contentType = $this->repository->getContentTypeService()->loadContentType(
- $content->getVersionInfo()->getContentInfo()->contentTypeId
- );
- $relations = $this->relationListFacade->getRelations($contentValue->getVersionInfo());
- }
-
- return new Values\CreatedContent(
- [
- 'content' => new Values\RestContent(
- $content->contentInfo,
- null,
- $contentValue,
- $contentType,
- $relations !== null ? iterator_to_array($relations) : null,
- ),
- ]
- );
- }
-
- /**
- * @return string[]
- */
- protected function getLanguages(Request $request): array
- {
- $languages = Language::ALL;
- if ($request->query->has('languages')) {
- /** @var string $languagesString */
- $languagesString = $request->query->get('languages');
- $languages = explode(',', $languagesString);
- }
-
- return $languages;
- }
-}
diff --git a/src/lib/Server/Controller/Content/ContentCopyController.php b/src/lib/Server/Controller/Content/ContentCopyController.php
new file mode 100644
index 000000000..3b49eeed6
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentCopyController.php
@@ -0,0 +1,73 @@
+headers->get('Destination');
+
+ $parentLocationParts = explode('/', $destination);
+ $copiedContent = $this->repository->getContentService()->copyContent(
+ $this->repository->getContentService()->loadContentInfo($contentId),
+ $this->repository->getLocationService()->newLocationCreateStruct(array_pop($parentLocationParts))
+ );
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_content',
+ ['contentId' => $copiedContent->id]
+ )
+ );
+ }
+
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ */
+ public function copy(int $contentId, Request $request): Values\ResourceCreated
+ {
+ $contentService = $this->repository->getContentService();
+ $locationService = $this->repository->getLocationService();
+
+ $contentInfo = $contentService->loadContentInfo($contentId);
+
+ /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $destinationLocation */
+ $destinationLocation = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent(),
+ ),
+ );
+
+ $copiedContent = $contentService->copyContent(
+ $contentInfo,
+ $locationService->newLocationCreateStruct($destinationLocation->getId()),
+ );
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_content',
+ ['contentId' => $copiedContent->id],
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentCreateController.php b/src/lib/Server/Controller/Content/ContentCreateController.php
new file mode 100644
index 000000000..53a1fc6de
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentCreateController.php
@@ -0,0 +1,191 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a draft assigned to the authenticated user. If a different user ID is given in the input, the draft is assigned to the given user but this action requires special permissions for the authenticated user (this is useful for content staging where the transfer process does not have to authenticate with the user who created the content item in the source server). The user needs to publish the content item if it should be visible.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'Content - If set, all information for the content item including the embedded current version is returned in XML or JSON format. ContentInfo - If set, all information for the content item (excluding the current version) is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The ContentCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/POST/ContentCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Content+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Content',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Content+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.json.example',
+ ],
+ 'application/vnd.ibexa.api.ContentInfo+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition or the validation on a field fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this Object in this Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the parent Location specified in the request body does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentCreateController extends RestController
+{
+ /**
+ * Creates a new content draft assigned to the authenticated user.
+ * If a different userId is given in the input it is assigned to the
+ * given user but this required special rights for the authenticated
+ * user (this is useful for content staging where the transfer process
+ * does not have to authenticate with the user which created the content
+ * object in the source server). The user has to publish the content if
+ * it should be visible.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedContent
+ */
+ public function createContent(Request $request)
+ {
+ $contentCreate = $this->parseContentRequest($request);
+
+ return $this->doCreateContent($request, $contentCreate);
+ }
+
+ /**
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *
+ * @return mixed
+ */
+ protected function parseContentRequest(Request $request)
+ {
+ return $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type'), 'Url' => $request->getPathInfo()],
+ $request->getContent()
+ )
+ );
+ }
+
+ /**
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * @param \Ibexa\Rest\Server\Values\RestContentCreateStruct $contentCreate
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedContent
+ */
+ protected function doCreateContent(Request $request, RestContentCreateStruct $contentCreate)
+ {
+ try {
+ $contentCreateStruct = $contentCreate->contentCreateStruct;
+ $contentCreate->locationCreateStruct->sortField = $contentCreateStruct->contentType->defaultSortField;
+ $contentCreate->locationCreateStruct->sortOrder = $contentCreateStruct->contentType->defaultSortOrder;
+
+ $content = $this->repository->getContentService()->createContent(
+ $contentCreateStruct,
+ [$contentCreate->locationCreateStruct]
+ );
+ } catch (ContentValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (ContentFieldValidationException $e) {
+ throw new RESTContentFieldValidationException($e);
+ }
+
+ $contentValue = null;
+ $contentType = null;
+ $relations = null;
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.content') {
+ $contentValue = $content;
+ $contentType = $this->repository->getContentTypeService()->loadContentType(
+ $content->getVersionInfo()->getContentInfo()->contentTypeId
+ );
+ $relations = $this->repository->getContentService()->loadRelations($contentValue->getVersionInfo());
+ }
+
+ return new Values\CreatedContent(
+ [
+ 'content' => new Values\RestContent(
+ $content->contentInfo,
+ null,
+ $contentValue,
+ $contentType,
+ $relations
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentCurrentVersionRedirectController.php b/src/lib/Server/Controller/Content/ContentCurrentVersionRedirectController.php
new file mode 100644
index 000000000..eb41ddb1e
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentCurrentVersionRedirectController.php
@@ -0,0 +1,83 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Version+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Version',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Version+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_TEMPORARY_REDIRECT => [
+ 'description' => 'Temporary redirect.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the resource does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentCurrentVersionRedirectController extends RestController
+{
+ /**
+ * Loads a specific version of a given content object.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
+ */
+ public function redirectCurrentVersion($contentId)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate(
+ 'ibexa.rest.load_content_in_version',
+ [
+ 'contentId' => $contentId,
+ 'versionNumber' => $contentInfo->currentVersionNo,
+ ]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentCurrentVersionRelationsRedirectController.php b/src/lib/Server/Controller/Content/ContentCurrentVersionRelationsRedirectController.php
new file mode 100644
index 000000000..ef04ecd5f
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentCurrentVersionRelationsRedirectController.php
@@ -0,0 +1,70 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_TEMPORARY_REDIRECT => [
+ 'description' => 'Temporary redirect.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item was not found.',
+ ],
+ ],
+ ),
+)]
+class ContentCurrentVersionRelationsRedirectController extends RestController
+{
+ /**
+ * Redirects to the relations of the current version.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
+ */
+ public function redirectCurrentVersionRelations($contentId)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate(
+ 'ibexa.rest.redirect_current_version_relations',
+ [
+ 'contentId' => $contentId,
+ 'versionNumber' => $contentInfo->currentVersionNo,
+ ]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentDeleteController.php b/src/lib/Server/Controller/Content/ContentDeleteController.php
new file mode 100644
index 000000000..fe2293284
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentDeleteController.php
@@ -0,0 +1,65 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'The content item is deleted.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - content item was not found.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this content item.',
+ ],
+ ],
+ ),
+)]
+class ContentDeleteController extends RestController
+{
+ /**
+ * The content is deleted. If the content has locations (which is required in 4.x)
+ * on delete all locations assigned the content object are deleted via delete subtree.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteContent($contentId)
+ {
+ $this->repository->getContentService()->deleteContent(
+ $this->repository->getContentService()->loadContentInfo($contentId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentDraftCreateFromCurrentVersionController.php b/src/lib/Server/Controller/Content/ContentDraftCreateFromCurrentVersionController.php
new file mode 100644
index 000000000..bda8f006e
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentDraftCreateFromCurrentVersionController.php
@@ -0,0 +1,114 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'The system creates a new draft as a copy of the current version. COPY or POST with header X-HTTP-Method-Override COPY.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated version is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Created',
+ 'content' => [
+ 'application/vnd.ibexa.api.Version+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Version',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Version+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update this content item.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the current version is already a draft.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item was not found.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentDraftCreateFromCurrentVersionController extends RestController
+{
+ /**
+ * The system creates a new draft version as a copy from the current version.
+ *
+ * @param mixed $contentId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if the current version is already a draft
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedVersion
+ */
+ public function createDraftFromCurrentVersion($contentId)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
+ $versionInfo = $this->repository->getContentService()->loadVersionInfo(
+ $contentInfo
+ );
+
+ if ($versionInfo->isDraft()) {
+ throw new ForbiddenException('Current version already has DRAFT status');
+ }
+
+ $contentDraft = $this->repository->getContentService()->createContentDraft($contentInfo);
+
+ return new Values\CreatedVersion(
+ [
+ 'version' => new Values\Version(
+ $contentDraft,
+ $contentType,
+ $this->repository->getContentService()->loadRelations($contentDraft->getVersionInfo())
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentDraftCreateFromVersionController.php b/src/lib/Server/Controller/Content/ContentDraftCreateFromVersionController.php
new file mode 100644
index 000000000..a0e0290ef
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentDraftCreateFromVersionController.php
@@ -0,0 +1,112 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'The system creates a new draft as a copy of the given version. COPY or POST with header X-HTTP-Method-Override COPY.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated version is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Version+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Version',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Version+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item was not found.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentDraftCreateFromVersionController extends RestController
+{
+ /**
+ * The system creates a new draft version as a copy from the given version.
+ *
+ * @param mixed $contentId
+ * @param mixed $versionNumber
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedVersion
+ */
+ public function createDraftFromVersion($contentId, $versionNumber)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
+ $contentDraft = $this->repository->getContentService()->createContentDraft(
+ $contentInfo,
+ $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber)
+ );
+
+ return new Values\CreatedVersion(
+ [
+ 'version' => new Values\Version(
+ $contentDraft,
+ $contentType,
+ $this->repository->getContentService()->loadRelations($contentDraft->getVersionInfo())
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentDraftTranslationDeleteController.php b/src/lib/Server/Controller/Content/ContentDraftTranslationDeleteController.php
new file mode 100644
index 000000000..9d2cc6134
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentDraftTranslationDeleteController.php
@@ -0,0 +1,99 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'languageCode',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - removes a translation from a version draft.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this translation.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the version is not in draft state.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item or version number were not found.',
+ ],
+ Response::HTTP_NOT_ACCEPTABLE => [
+ 'description' => 'Error - the given translation does not exist for the version.',
+ ],
+ Response::HTTP_CONFLICT => [
+ 'description' => 'Error - the specified translation is the only one the version has or is the main translation.',
+ ],
+ ],
+ ),
+)]
+class ContentDraftTranslationDeleteController extends RestController
+{
+ /**
+ * Remove the given Translation from the given Version Draft.
+ *
+ * @param int $contentId
+ * @param int $versionNumber
+ * @param string $languageCode
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ */
+ public function deleteTranslationFromDraft($contentId, $versionNumber, $languageCode)
+ {
+ $contentService = $this->repository->getContentService();
+ $versionInfo = $contentService->loadVersionInfoById($contentId, $versionNumber);
+
+ if (!$versionInfo->isDraft()) {
+ throw new ForbiddenException('Translation can be deleted from a DRAFT version only');
+ }
+
+ $contentService->deleteTranslationFromDraft($versionInfo, $languageCode);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentHideController.php b/src/lib/Server/Controller/Content/ContentHideController.php
new file mode 100644
index 000000000..18a5c793f
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentHideController.php
@@ -0,0 +1,66 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Makes or keep the content item invisible',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'OK - Object item is hidden.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to change Object item visibility.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content item was not found.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentHideController extends RestController
+{
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ */
+ public function hideContent(int $contentId): Values\NoContent
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ $this->repository->getContentService()->hideContent($contentInfo);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentInVersionLoadController.php b/src/lib/Server/Controller/Content/ContentInVersionLoadController.php
new file mode 100644
index 000000000..e0620917e
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentInVersionLoadController.php
@@ -0,0 +1,134 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the version list is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Version+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Version',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Version+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_MODIFIED => [
+ 'description' => 'Error - the ETag does not match the current one.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the ID or version is not found.',
+ ],
+ ],
+ ),
+)]
+class ContentInVersionLoadController extends RestController
+{
+ /**
+ * Loads a specific version of a given content object.
+ *
+ * @param mixed $contentId
+ * @param int $versionNumber
+ *
+ * @return \Ibexa\Rest\Server\Values\Version
+ */
+ public function loadContentInVersion($contentId, $versionNumber, Request $request)
+ {
+ $languages = Language::ALL;
+ if ($request->query->has('languages')) {
+ $languages = explode(',', $request->query->get('languages'));
+ }
+
+ $content = $this->repository->getContentService()->loadContent(
+ $contentId,
+ $languages,
+ $versionNumber
+ );
+ $contentType = $this->repository->getContentTypeService()->loadContentType(
+ $content->getVersionInfo()->getContentInfo()->contentTypeId
+ );
+
+ $versionValue = new Values\Version(
+ $content,
+ $contentType,
+ $this->repository->getContentService()->loadRelations($content->getVersionInfo()),
+ $request->getPathInfo()
+ );
+
+ if ($content->contentInfo->mainLocationId === null || $content->versionInfo->status === VersionInfo::STATUS_DRAFT) {
+ return $versionValue;
+ }
+
+ return new Values\CachedValue(
+ $versionValue,
+ ['locationId' => $content->contentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentLoadByIdController.php b/src/lib/Server/Controller/Content/ContentLoadByIdController.php
new file mode 100644
index 000000000..6148492c5
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentLoadByIdController.php
@@ -0,0 +1,142 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'If the provided ETag matches the current ETag then a "304 Not Modified" is returned. The ETag changes if the meta data has changed, this happens also if there is a new published version.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Content+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Content',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Content+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/GET/Content.json.example',
+ ],
+ 'application/vnd.ibexa.api.ContentInfo+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfo',
+ ],
+ ],
+ 'application/vnd.ibexa.api.ContentInfo+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this object. This could also happen if there is no published version yet and another user owns a draft of this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the ID is not found.',
+ ],
+ ],
+ ),
+)]
+class ContentLoadByIdController extends RestController
+{
+ /**
+ * Loads a content info, potentially with the current version embedded.
+ *
+ * @param mixed $contentId
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContent
+ */
+ public function loadContent($contentId, Request $request)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ $mainLocation = null;
+ if (!empty($contentInfo->mainLocationId)) {
+ $mainLocation = $this->repository->getLocationService()->loadLocation($contentInfo->mainLocationId);
+ }
+
+ $contentType = $this->repository->getContentTypeService()->loadContentType($contentInfo->contentTypeId);
+
+ $contentVersion = null;
+ $relations = null;
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.content') {
+ $languages = Language::ALL;
+ if ($request->query->has('languages')) {
+ $languages = explode(',', $request->query->get('languages'));
+ }
+
+ $contentVersion = $this->repository->getContentService()->loadContent($contentId, $languages);
+ $relations = $this->repository->getContentService()->loadRelations($contentVersion->getVersionInfo());
+ }
+
+ $restContent = new Values\RestContent(
+ $contentInfo,
+ $mainLocation,
+ $contentVersion,
+ $contentType,
+ $relations,
+ $request->getPathInfo()
+ );
+
+ if ($contentInfo->mainLocationId === null) {
+ return $restContent;
+ }
+
+ return new Values\CachedValue(
+ $restContent,
+ ['locationId' => $contentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentMetadataUpdateController.php b/src/lib/Server/Controller/Content/ContentMetadataUpdateController.php
new file mode 100644
index 000000000..7f69517a0
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentMetadataUpdateController.php
@@ -0,0 +1,166 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'This method updates the content metadata which is independent from a version. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, all information for the content item (excluding the current version) is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-match',
+ in: 'header',
+ required: true,
+ description: 'Causes to patch only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The ContentUpdate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfo',
+ ],
+ ],
+ 'application/vnd.ibexa.api.ContentUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentInfo+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfo',
+ ],
+ ],
+ 'application/vnd.ibexa.api.ContentInfo+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/PATCH/ContentInfo.xml.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update this object.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content ID does not exist.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ Response::HTTP_UNSUPPORTED_MEDIA_TYPE => [
+ 'description' => 'Error - the media-type is not one of those specified in headers.',
+ ],
+ ],
+ ),
+)]
+class ContentMetadataUpdateController extends RestController
+{
+ /**
+ * Updates a content's metadata.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContent
+ */
+ public function updateContentMetadata($contentId, Request $request)
+ {
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ // update section
+ if ($updateStruct->sectionId !== null) {
+ $section = $this->repository->getSectionService()->loadSection($updateStruct->sectionId);
+ $this->repository->getSectionService()->assignSection($contentInfo, $section);
+ $updateStruct->sectionId = null;
+ }
+
+ // @todo Consider refactoring! ContentService::updateContentMetadata throws the same exception
+ // in case the updateStruct is empty and if remoteId already exists. Since REST version of update struct
+ // includes section ID in addition to other fields, we cannot throw exception if only sectionId property
+ // is set, so we must skip updating content in that case instead of allowing propagation of the exception.
+ foreach ($updateStruct as $propertyName => $propertyValue) {
+ if ($propertyName !== 'sectionId' && $propertyValue !== null) {
+ // update content
+ $this->repository->getContentService()->updateContentMetadata($contentInfo, $updateStruct);
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ break;
+ }
+ }
+
+ try {
+ $locationInfo = $this->repository->getLocationService()->loadLocation($contentInfo->mainLocationId);
+ } catch (NotFoundException $e) {
+ $locationInfo = null;
+ }
+
+ return new Values\RestContent(
+ $contentInfo,
+ $locationInfo
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentRedirectController.php b/src/lib/Server/Controller/Content/ContentRedirectController.php
new file mode 100644
index 000000000..cd81dc6eb
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentRedirectController.php
@@ -0,0 +1,69 @@
+ [
+ 'description' => 'Temporary redirect.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content with the given remote ID does not exist.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentRedirectController extends RestController
+{
+ /**
+ * Loads a content info by remote ID.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ *
+ * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
+ */
+ public function redirectContent(Request $request)
+ {
+ if (!$request->query->has('remoteId')) {
+ throw new BadRequestException("'remoteId' parameter is required.");
+ }
+
+ $contentInfo = $this->repository->getContentService()->loadContentInfoByRemoteId(
+ $request->query->get('remoteId')
+ );
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate(
+ 'ibexa.rest.load_content',
+ [
+ 'contentId' => $contentInfo->id,
+ ]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentRelationCreateController.php b/src/lib/Server/Controller/Content/ContentRelationCreateController.php
new file mode 100644
index 000000000..cc56e7b7f
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentRelationCreateController.php
@@ -0,0 +1,153 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Relation of type COMMON for the given draft.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated version is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RelationCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RelationCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RelationCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/RelationCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Relation+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Relation',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/relation_id/GET/Relation.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Relation+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.json.example',
+ ],
+ ],
+ ],
+ ],
+ ),
+)]
+class ContentRelationCreateController extends RestController
+{
+ /**
+ * Creates a new relation of type COMMON for the given draft.
+ *
+ * @param mixed $contentId
+ * @param int $versionNumber
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if version $versionNumber isn't a draft
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException if a relation to the same content already exists
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedRelation
+ */
+ public function createRelation($contentId, $versionNumber, Request $request)
+ {
+ $destinationContentId = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ $versionInfo = $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber);
+ if (!$versionInfo->isDraft()) {
+ throw new ForbiddenException('Relation of type COMMON can only be added to drafts');
+ }
+
+ try {
+ $destinationContentInfo = $this->repository->getContentService()->loadContentInfo($destinationContentId);
+ } catch (NotFoundException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ $existingRelations = $this->repository->getContentService()->loadRelations($versionInfo);
+ foreach ($existingRelations as $existingRelation) {
+ if ($existingRelation->getDestinationContentInfo()->id == $destinationContentId) {
+ throw new ForbiddenException('Relation of type COMMON to the selected destination content ID already exists');
+ }
+ }
+
+ $relation = $this->repository->getContentService()->addRelation($versionInfo, $destinationContentInfo);
+
+ return new Values\CreatedRelation(
+ [
+ 'relation' => new Values\RestRelation($relation, $contentId, $versionNumber),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentRevealController.php b/src/lib/Server/Controller/Content/ContentRevealController.php
new file mode 100644
index 000000000..333f5deda
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentRevealController.php
@@ -0,0 +1,66 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Makes or keep the content item visible',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'OK - Object item is revealed.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to change Object item visibility.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content item was not found.',
+ ],
+ ],
+ ),
+)]
+class ContentRevealController extends RestController
+{
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ */
+ public function revealContent(int $contentId): Values\NoContent
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ $this->repository->getContentService()->revealContent($contentInfo);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentTranslationDeleteController.php b/src/lib/Server/Controller/Content/ContentTranslationDeleteController.php
new file mode 100644
index 000000000..72c567cf3
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentTranslationDeleteController.php
@@ -0,0 +1,95 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'languageCode',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete content item (content/remove policy).',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item was not found.',
+ ],
+ Response::HTTP_NOT_ACCEPTABLE => [
+ 'description' => 'Error - the given translation does not exist for the content item.',
+ ],
+ Response::HTTP_CONFLICT => [
+ 'description' => 'Error - the specified translation is the only one any version has or is the main translation.',
+ ],
+ ],
+ ),
+)]
+class ContentTranslationDeleteController extends RestController
+{
+ /**
+ * Deletes a translation from all the Versions of the given Content Object.
+ *
+ * If any non-published Version contains only the Translation to be deleted, that entire Version will be deleted
+ *
+ * @param int $contentId
+ * @param string $languageCode
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ *
+ * @throws \Exception
+ */
+ public function deleteContentTranslation($contentId, $languageCode)
+ {
+ $contentService = $this->repository->getContentService();
+
+ $this->repository->beginTransaction();
+ try {
+ $contentInfo = $contentService->loadContentInfo($contentId);
+ $contentService->deleteTranslation(
+ $contentInfo,
+ $languageCode
+ );
+
+ $this->repository->commit();
+
+ return new Values\NoContent();
+ } catch (\Exception $e) {
+ $this->repository->rollback();
+ throw $e;
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionDeleteController.php b/src/lib/Server/Controller/Content/ContentVersionDeleteController.php
new file mode 100644
index 000000000..52d357b78
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionDeleteController.php
@@ -0,0 +1,88 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - the version is deleted.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item or version were not found.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this version.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the version is in published state.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionDeleteController extends RestController
+{
+ /**
+ * The version is deleted.
+ *
+ * @param mixed $contentId
+ * @param mixed $versionNumber
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteContentVersion($contentId, $versionNumber)
+ {
+ $versionInfo = $this->repository->getContentService()->loadVersionInfo(
+ $this->repository->getContentService()->loadContentInfo($contentId),
+ $versionNumber
+ );
+
+ if ($versionInfo->isPublished()) {
+ throw new ForbiddenException('Versions with PUBLISHED status cannot be deleted');
+ }
+
+ $this->repository->getContentService()->deleteVersion(
+ $versionInfo
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionPublishController.php b/src/lib/Server/Controller/Content/ContentVersionPublishController.php
new file mode 100644
index 000000000..b905180c8
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionPublishController.php
@@ -0,0 +1,43 @@
+repository->getContentService()->loadVersionInfo(
+ $this->repository->getContentService()->loadContentInfo($contentId),
+ $versionNumber
+ );
+
+ if (!$versionInfo->isDraft()) {
+ throw new ForbiddenException('Only versions with DRAFT status can be published');
+ }
+
+ $this->repository->getContentService()->publishVersion(
+ $versionInfo
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionRelationDeleteController.php b/src/lib/Server/Controller/Content/ContentVersionRelationDeleteController.php
new file mode 100644
index 000000000..e2b663cb8
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionRelationDeleteController.php
@@ -0,0 +1,110 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'relationId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - deleted a Relation of the given draft.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this Relation.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the Relation is not of type COMMON or the given version is not a draft.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - content item or the Relation were not found in the given version.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionRelationDeleteController extends RestController
+{
+ /**
+ * Deletes a relation of the given draft.
+ *
+ * @param mixed $contentId
+ * @param int $versionNumber
+ * @param mixed $relationId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function removeRelation($contentId, $versionNumber, $relationId, Request $request)
+ {
+ $versionInfo = $this->repository->getContentService()->loadVersionInfo(
+ $this->repository->getContentService()->loadContentInfo($contentId),
+ $versionNumber
+ );
+
+ $versionRelations = $this->repository->getContentService()->loadRelations($versionInfo);
+ foreach ($versionRelations as $relation) {
+ if ($relation->id == $relationId) {
+ if ($relation->type !== Relation::COMMON) {
+ throw new ForbiddenException('Relation is not of type COMMON');
+ }
+
+ if (!$versionInfo->isDraft()) {
+ throw new ForbiddenException('Relation of type COMMON can only be removed from drafts');
+ }
+
+ $this->repository->getContentService()->deleteRelation($versionInfo, $relation->getDestinationContentInfo());
+
+ return new Values\NoContent();
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Could not find Relation '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionRelationLoadByIdController.php b/src/lib/Server/Controller/Content/ContentVersionRelationLoadByIdController.php
new file mode 100644
index 000000000..1b44c6593
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionRelationLoadByIdController.php
@@ -0,0 +1,126 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'relationId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - loads a Relation for the given content item.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Relation+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Relation',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/relation_id/GET/Relation.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Relation+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/POST/Relation.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item with the given ID or the Relation does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionRelationLoadByIdController extends RestController
+{
+ /**
+ * Loads a relation for the given content object and version.
+ *
+ * @param mixed $contentId
+ * @param int $versionNumber
+ * @param mixed $relationId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestRelation
+ */
+ public function loadVersionRelation($contentId, $versionNumber, $relationId, Request $request)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ $relationList = $this->repository->getContentService()->loadRelations(
+ $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber)
+ );
+
+ foreach ($relationList as $relation) {
+ if ($relation->id == $relationId) {
+ $relation = new Values\RestRelation($relation, $contentId, $versionNumber);
+
+ if ($contentInfo->mainLocationId === null) {
+ return $relation;
+ }
+
+ return new Values\CachedValue(
+ $relation,
+ ['locationId' => $contentInfo->mainLocationId]
+ );
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Relation not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionUpdateController.php b/src/lib/Server/Controller/Content/ContentVersionUpdateController.php
new file mode 100644
index 000000000..4e98a7ec2
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionUpdateController.php
@@ -0,0 +1,199 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'A specific draft is updated. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated version is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-match',
+ in: 'header',
+ required: true,
+ description: 'Performs the patch only if the specified ETag is the current one.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The VersionUpdate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.VersionUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/PATCH/VersionUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.VersionUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionUpdateWrapper',
+ ],
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Version+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Version',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Version+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/GET/Version.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update this version.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the version is not allowed to change - i.e. version is not a DRAFT.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content ID or version ID does not exist.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionUpdateController extends RestController
+{
+ /**
+ * A specific draft is updated.
+ *
+ * @param mixed $contentId
+ * @param mixed $versionNumber
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ *
+ * @return \Ibexa\Rest\Server\Values\Version
+ */
+ public function updateVersion($contentId, $versionNumber, Request $request)
+ {
+ $contentUpdateStruct = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ 'Url' => $this->router->generate(
+ 'ibexa.rest.update_version',
+ [
+ 'contentId' => $contentId,
+ 'versionNumber' => $versionNumber,
+ ]
+ ),
+ ],
+ $request->getContent()
+ )
+ );
+
+ $versionInfo = $this->repository->getContentService()->loadVersionInfo(
+ $this->repository->getContentService()->loadContentInfo($contentId),
+ $versionNumber
+ );
+
+ if (!$versionInfo->isDraft()) {
+ throw new ForbiddenException('Only versions with DRAFT status can be updated');
+ }
+
+ try {
+ $this->repository->getContentService()->updateContent($versionInfo, $contentUpdateStruct);
+ } catch (ContentValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (ContentFieldValidationException $e) {
+ throw new RESTContentFieldValidationException($e);
+ }
+
+ $languages = null;
+ if ($request->query->has('languages')) {
+ $languages = explode(',', $request->query->get('languages'));
+ }
+
+ // Reload the content to handle languages GET parameter
+ $content = $this->repository->getContentService()->loadContent(
+ $contentId,
+ $languages,
+ $versionInfo->versionNo
+ );
+ $contentType = $this->repository->getContentTypeService()->loadContentType(
+ $content->getVersionInfo()->getContentInfo()->contentTypeId
+ );
+
+ return new Values\Version(
+ $content,
+ $contentType,
+ $this->repository->getContentService()->loadRelations($content->getVersionInfo()),
+ $request->getPathInfo()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionsListController.php b/src/lib/Server/Controller/Content/ContentVersionsListController.php
new file mode 100644
index 000000000..d11276e76
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionsListController.php
@@ -0,0 +1,86 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.VersionList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.VersionList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/GET/VersionList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read the versions.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionsListController extends RestController
+{
+ /**
+ * Returns a list of all versions of the content. This method does not
+ * include fields and relations in the Version elements of the response.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\VersionList
+ */
+ public function loadContentVersions($contentId, Request $request)
+ {
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+
+ return new Values\VersionList(
+ $this->repository->getContentService()->loadVersions($contentInfo),
+ $request->getPathInfo()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentVersionsRelationsListController.php b/src/lib/Server/Controller/Content/ContentVersionsRelationsListController.php
new file mode 100644
index 000000000..ee2578d77
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentVersionsRelationsListController.php
@@ -0,0 +1,120 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'versionNo',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RelationList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RelationList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RelationListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/versions/version_no/relations/GET/RelationList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item was not found.',
+ ],
+ ],
+ ),
+)]
+class ContentVersionsRelationsListController extends RestController
+{
+ /**
+ * Loads the relations of the given version.
+ *
+ * @param mixed $contentId
+ * @param mixed $versionNumber
+ *
+ * @return \Ibexa\Rest\Server\Values\RelationList
+ */
+ public function loadVersionRelations($contentId, $versionNumber, Request $request)
+ {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
+
+ $contentInfo = $this->repository->getContentService()->loadContentInfo($contentId);
+ $relationList = $this->repository->getContentService()->loadRelations(
+ $this->repository->getContentService()->loadVersionInfo($contentInfo, $versionNumber)
+ );
+
+ $relationList = array_slice(
+ $relationList,
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : null
+ );
+
+ $relationListValue = new Values\RelationList(
+ $relationList,
+ $contentId,
+ $versionNumber,
+ $request->getPathInfo()
+ );
+
+ if ($contentInfo->mainLocationId === null) {
+ return $relationListValue;
+ }
+
+ return new Values\CachedValue(
+ $relationListValue,
+ ['locationId' => $contentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Content/ContentViewController.php b/src/lib/Server/Controller/Content/ContentViewController.php
new file mode 100644
index 000000000..41612e3fd
--- /dev/null
+++ b/src/lib/Server/Controller/Content/ContentViewController.php
@@ -0,0 +1,91 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Executes a query and returns View including the results. The View input reflects the criteria model of the public PHP API. Deprecated as of eZ Platform 1.0 and will respond 301, use POST /views instead.',
+ tags: [
+ 'Views',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'The View in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The View input in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_MOVED_PERMANENTLY => [
+ 'description' => 'Moved permanently.',
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentViewController extends RestController
+{
+ /**
+ * Creates and executes a content view.
+ *
+ * @deprecated Since platform 1.0. Forwards the request to the new /views location, but returns a 301.
+ *
+ * @return \Ibexa\Rest\Server\Values\RestExecutedView
+ */
+ public function createView()
+ {
+ $response = $this->forward('ezpublish_rest.controller.views:createView');
+
+ // Add 301 status code and location href
+ $response->setStatusCode(Response::HTTP_MOVED_PERMANENTLY);
+ $response->headers->set('Location', $this->router->generate('ibexa.rest.views.create'));
+
+ return $response;
+ }
+
+ /**
+ * @param string $controller
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ */
+ protected function forward($controller)
+ {
+ $path['_controller'] = $controller;
+ $subRequest = $this->container->get('request_stack')->getCurrentRequest()->duplicate(null, null, $path);
+
+ return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType.php b/src/lib/Server/Controller/ContentType.php
deleted file mode 100644
index 849d4ee76..000000000
--- a/src/lib/Server/Controller/ContentType.php
+++ /dev/null
@@ -1,1006 +0,0 @@
-contentTypeService = $contentTypeService;
- }
-
- /**
- * Creates a new content type group.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedContentTypeGroup
- */
- public function createContentTypeGroup(Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- return new Values\CreatedContentTypeGroup(
- [
- 'contentTypeGroup' => $this->contentTypeService->createContentTypeGroup($createStruct),
- ]
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- /**
- * Updates a content type group.
- *
- * @param $contentTypeGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup
- */
- public function updateContentTypeGroup($contentTypeGroupId, Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- $this->contentTypeService->updateContentTypeGroup(
- $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId),
- $this->mapToGroupUpdateStruct($createStruct)
- );
-
- return $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL);
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- /**
- * Returns a list of content types of the group.
- *
- * @param string $contentTypeGroupId
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeList|\Ibexa\Rest\Server\Values\ContentTypeInfoList
- */
- public function listContentTypesForGroup($contentTypeGroupId, Request $request)
- {
- $contentTypes = $this->contentTypeService->loadContentTypes(
- $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL),
- Language::ALL
- );
-
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.contenttypelist') {
- return new Values\ContentTypeList($contentTypes, $request->getPathInfo());
- }
-
- return new Values\ContentTypeInfoList($contentTypes, $request->getPathInfo());
- }
-
- /**
- * The given content type group is deleted.
- *
- * @param mixed $contentTypeGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteContentTypeGroup($contentTypeGroupId)
- {
- $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
-
- $contentTypes = $this->contentTypeService->loadContentTypes($contentTypeGroup);
- if (!empty($contentTypes)) {
- throw new ForbiddenException('Only empty content type groups can be deleted');
- }
-
- $this->contentTypeService->deleteContentTypeGroup($contentTypeGroup);
-
- return new Values\NoContent();
- }
-
- /**
- * Returns a list of all content type groups.
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeGroupList
- */
- public function loadContentTypeGroupList(Request $request)
- {
- if ($request->query->has('identifier')) {
- /** @var string $identifier */
- $identifier = $request->query->get('identifier');
- $contentTypeGroup = $this->contentTypeService->loadContentTypeGroupByIdentifier(
- $identifier
- );
-
- return new Values\TemporaryRedirect(
- $this->router->generate(
- 'ibexa.rest.load_content_type_group',
- [
- 'contentTypeGroupId' => $contentTypeGroup->id,
- ]
- )
- );
- }
-
- return new Values\ContentTypeGroupList(
- $this->contentTypeService->loadContentTypeGroups(Language::ALL)
- );
- }
-
- /**
- * Returns the content type group given by id.
- *
- * @param $contentTypeGroupId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup
- */
- public function loadContentTypeGroup($contentTypeGroupId)
- {
- return $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL);
- }
-
- /**
- * Loads a content type.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\RestContentType
- */
- public function loadContentType($contentTypeId)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
-
- return new Values\RestContentType(
- $contentType,
- $contentType->getFieldDefinitions()->toArray()
- );
- }
-
- /**
- * Returns a list of content types.
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeList|\Ibexa\Rest\Server\Values\ContentTypeInfoList
- */
- public function listContentTypes(Request $request)
- {
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.contenttypelist') {
- $return = new Values\ContentTypeList([], $request->getPathInfo());
- } else {
- $return = new Values\ContentTypeInfoList([], $request->getPathInfo());
- }
-
- if ($request->query->has('identifier')) {
- $return->contentTypes = [$this->loadContentTypeByIdentifier($request)];
-
- return $return;
- }
-
- if ($request->query->has('remoteId')) {
- $return->contentTypes = [
- $this->loadContentTypeByRemoteId($request),
- ];
-
- return $return;
- }
-
- $limit = null;
- if ($request->query->has('limit')) {
- $limit = (int)$request->query->get('limit', null);
- if ($limit <= 0) {
- throw new BadRequestException('wrong value for limit parameter');
- }
- }
- $contentTypes = $this->getContentTypeList();
- $sort = $request->query->get('sort');
- if ($request->query->has('orderby')) {
- /** @var string $orderby */
- $orderby = $request->query->get('orderby');
- $this->sortContentTypeList($contentTypes, $orderby, $sort);
- }
- $offset = $request->query->get('offset', 0);
- $return->contentTypes = array_slice($contentTypes, $offset, $limit);
-
- return $return;
- }
-
- /**
- * Loads a content type by its identifier.
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType
- */
- public function loadContentTypeByIdentifier(Request $request)
- {
- return $this->contentTypeService->loadContentTypeByIdentifier(
- $request->query->get('identifier'),
- Language::ALL
- );
- }
-
- /**
- * Loads a content type by its remote ID.
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType
- */
- public function loadContentTypeByRemoteId(Request $request)
- {
- return $this->contentTypeService->loadContentTypeByRemoteId(
- $request->query->get('remoteId'),
- Language::ALL
- );
- }
-
- /**
- * Creates a new content type draft in the given content type group.
- *
- * @param $contentTypeGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedContentType
- */
- public function createContentType($contentTypeGroupId, Request $request)
- {
- $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
- $publish = ($request->query->has('publish') && $request->query->get('publish') === 'true');
-
- try {
- $contentTypeDraft = $this->contentTypeService->createContentType(
- $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- // @todo Needs refactoring! Temporary solution so parser has access to get parameters
- '__publish' => $publish,
- ],
- $request->getContent()
- )
- ),
- [$contentTypeGroup]
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (ContentTypeValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (ContentTypeFieldDefinitionValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (Exceptions\Parser $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- if ($publish) {
- $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
-
- $contentType = $this->contentTypeService->loadContentType($contentTypeDraft->id, Language::ALL);
-
- return new Values\CreatedContentType(
- [
- 'contentType' => new Values\RestContentType(
- $contentType,
- $contentType->getFieldDefinitions()->toArray()
- ),
- ]
- );
- }
-
- return new Values\CreatedContentType(
- [
- 'contentType' => new Values\RestContentType(
- $contentTypeDraft,
- $contentTypeDraft->getFieldDefinitions()->toArray()
- ),
- ]
- );
- }
-
- /**
- * Copies a content type. The identifier of the copy is changed to
- * copy_of__ and a new remoteId is generated.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\ResourceCreated
- */
- public function copyContentType($contentTypeId)
- {
- $copiedContentType = $this->contentTypeService->copyContentType(
- $this->contentTypeService->loadContentType($contentTypeId)
- );
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_content_type',
- ['contentTypeId' => $copiedContentType->id]
- )
- );
- }
-
- /**
- * Creates a draft and updates it with the given data.
- *
- * @param $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedContentType
- */
- public function createContentTypeDraft($contentTypeId, Request $request)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
-
- try {
- $contentTypeDraft = $this->contentTypeService->createContentTypeDraft(
- $contentType
- );
- } catch (BadStateException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- $contentTypeUpdateStruct = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- ],
- $request->getContent()
- )
- );
-
- try {
- $this->contentTypeService->updateContentTypeDraft(
- $contentTypeDraft,
- $contentTypeUpdateStruct
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\CreatedContentType(
- [
- 'contentType' => new Values\RestContentType(
- // Reload the content type draft to get the updated values
- $this->contentTypeService->loadContentTypeDraft(
- $contentTypeDraft->id
- )
- ),
- ]
- );
- }
-
- /**
- * Loads a content type draft.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\RestContentType
- */
- public function loadContentTypeDraft($contentTypeId)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
-
- return new Values\RestContentType(
- $contentTypeDraft,
- $contentTypeDraft->getFieldDefinitions()->toArray()
- );
- }
-
- /**
- * Updates meta data of a draft. This method does not handle field definitions.
- *
- * @param $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\RestContentType
- */
- public function updateContentTypeDraft($contentTypeId, Request $request)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- $contentTypeUpdateStruct = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- ],
- $request->getContent()
- )
- );
-
- try {
- $this->contentTypeService->updateContentTypeDraft(
- $contentTypeDraft,
- $contentTypeUpdateStruct
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\RestContentType(
- // Reload the content type draft to get the updated values
- $this->contentTypeService->loadContentTypeDraft(
- $contentTypeDraft->id
- )
- );
- }
-
- /**
- * Creates a new field definition for the given content type draft.
- *
- * @param $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedFieldDefinition
- */
- public function addContentTypeDraftFieldDefinition($contentTypeId, Request $request)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- $fieldDefinitionCreate = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- ],
- $request->getContent()
- )
- );
-
- try {
- $this->contentTypeService->addFieldDefinition(
- $contentTypeDraft,
- $fieldDefinitionCreate
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (ContentTypeFieldDefinitionValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (BadStateException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- $updatedDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- foreach ($updatedDraft->getFieldDefinitions() as $fieldDefinition) {
- if ($fieldDefinition->identifier == $fieldDefinitionCreate->identifier) {
- return new Values\CreatedFieldDefinition(
- [
- 'fieldDefinition' => new Values\RestFieldDefinition($updatedDraft, $fieldDefinition),
- ]
- );
- }
- }
-
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Loads field definitions for a given content type.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
- *
- * @todo Check why this isn't in the specs
- */
- public function loadContentTypeFieldDefinitionList($contentTypeId)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
-
- return new Values\FieldDefinitionList(
- $contentType,
- $contentType->getFieldDefinitions()->toArray()
- );
- }
-
- /**
- * Returns the field definition given by id.
- *
- * @param $contentTypeId
- * @param $fieldDefinitionId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\RestFieldDefinition
- */
- public function loadContentTypeFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
-
- foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
- if ($fieldDefinition->id == $fieldDefinitionId) {
- return new Values\RestFieldDefinition(
- $contentType,
- $fieldDefinition
- );
- }
- }
-
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- */
- public function loadContentTypeFieldDefinitionByIdentifier(
- int $contentTypeId,
- string $fieldDefinitionIdentifier,
- Request $request
- ): Values\RestFieldDefinition {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
- $fieldDefinition = $contentType->getFieldDefinition($fieldDefinitionIdentifier);
- $path = $this->router->generate(
- 'ibexa.rest.load_content_type_field_definition_by_identifier',
- [
- 'contentTypeId' => $contentType->id,
- 'fieldDefinitionIdentifier' => $fieldDefinitionIdentifier,
- ]
- );
-
- if ($fieldDefinition === null) {
- throw new Exceptions\NotFoundException(
- sprintf("Field definition not found: '%s'.", $request->getPathInfo())
- );
- }
-
- return new Values\RestFieldDefinition(
- $contentType,
- $fieldDefinition,
- $path
- );
- }
-
- /**
- * Loads field definitions for a given content type draft.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
- */
- public function loadContentTypeDraftFieldDefinitionList($contentTypeId)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
-
- return new Values\FieldDefinitionList(
- $contentTypeDraft,
- $contentTypeDraft->getFieldDefinitions()
- );
- }
-
- /**
- * Returns the draft field definition given by id.
- *
- * @param $contentTypeId
- * @param $fieldDefinitionId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\RestFieldDefinition
- */
- public function loadContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
-
- foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDefinition) {
- if ($fieldDefinition->id == $fieldDefinitionId) {
- return new Values\RestFieldDefinition(
- $contentTypeDraft,
- $fieldDefinition
- );
- }
- }
-
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Updates the attributes of a field definition.
- *
- * @param $contentTypeId
- * @param $fieldDefinitionId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
- */
- public function updateContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- $fieldDefinitionUpdate = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- // @todo Needs refactoring! Temporary solution so parser has access to URL
- 'Url' => $request->getPathInfo(),
- ],
- $request->getContent()
- )
- );
-
- $fieldDefinition = null;
- foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDef) {
- if ($fieldDef->id == $fieldDefinitionId) {
- $fieldDefinition = $fieldDef;
- }
- }
-
- if ($fieldDefinition === null) {
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- try {
- $this->contentTypeService->updateFieldDefinition(
- $contentTypeDraft,
- $fieldDefinition,
- $fieldDefinitionUpdate
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- $updatedDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- foreach ($updatedDraft->getFieldDefinitions() as $fieldDef) {
- if ($fieldDef->id == $fieldDefinitionId) {
- return new Values\RestFieldDefinition($updatedDraft, $fieldDef);
- }
- }
-
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Deletes a field definition from a content type draft.
- *
- * @param $contentTypeId
- * @param $fieldDefinitionId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function removeContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
-
- $fieldDefinition = null;
- foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDef) {
- if ($fieldDef->id == $fieldDefinitionId) {
- $fieldDefinition = $fieldDef;
- }
- }
-
- if ($fieldDefinition === null) {
- throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
- }
-
- $this->contentTypeService->removeFieldDefinition(
- $contentTypeDraft,
- $fieldDefinition
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Publishes a content type draft.
- *
- * @param $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\RestContentType
- */
- public function publishContentTypeDraft($contentTypeId)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
-
- $fieldDefinitions = $contentTypeDraft->getFieldDefinitions();
- if (empty($fieldDefinitions)) {
- throw new ForbiddenException('Cannot publish an empty content type draft');
- }
-
- $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
-
- $publishedContentType = $this->contentTypeService->loadContentType($contentTypeDraft->id, Language::ALL);
-
- return new Values\RestContentType(
- $publishedContentType,
- $publishedContentType->getFieldDefinitions()->toArray()
- );
- }
-
- /**
- * The given content type is deleted.
- *
- * @param $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteContentType($contentTypeId)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
-
- try {
- $this->contentTypeService->deleteContentType($contentType);
- } catch (BadStateException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\NoContent();
- }
-
- /**
- * The given content type draft is deleted.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteContentTypeDraft($contentTypeId)
- {
- $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
- $this->contentTypeService->deleteContentType($contentTypeDraft);
-
- return new Values\NoContent();
- }
-
- /**
- * Returns the content type groups the content type belongs to.
- *
- * @param $contentTypeId
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
- */
- public function loadGroupsOfContentType($contentTypeId)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
-
- return new Values\ContentTypeGroupRefList(
- $contentType,
- $contentType->getContentTypeGroups()
- );
- }
-
- /**
- * Links a content type group to the content type and returns the updated group list.
- *
- * @param mixed $contentTypeId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
- */
- public function linkContentTypeToGroup($contentTypeId, Request $request)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
-
- try {
- $contentTypeGroupId = $this->uriParser->getAttributeFromUri(
- $request->query->get('group'),
- 'contentTypeGroupId'
- );
- } catch (Exceptions\InvalidArgumentException $e) {
- // Group URI does not match the required value
- throw new BadRequestException($e->getMessage());
- }
-
- $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
-
- $existingContentTypeGroups = $contentType->getContentTypeGroups();
- $contentTypeInGroup = false;
- foreach ($existingContentTypeGroups as $existingGroup) {
- if ($existingGroup->id == $contentTypeGroup->id) {
- $contentTypeInGroup = true;
- break;
- }
- }
-
- if ($contentTypeInGroup) {
- throw new ForbiddenException('The content type is already linked to the provided group');
- }
-
- $this->contentTypeService->assignContentTypeGroup(
- $contentType,
- $contentTypeGroup
- );
-
- $existingContentTypeGroups[] = $contentTypeGroup;
-
- return new Values\ContentTypeGroupRefList(
- $contentType,
- $existingContentTypeGroups
- );
- }
-
- /**
- * Removes the given group from the content type and returns the updated group list.
- *
- * @param $contentTypeId
- * @param $contentTypeGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
- */
- public function unlinkContentTypeFromGroup($contentTypeId, $contentTypeGroupId)
- {
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
- $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
-
- $existingContentTypeGroups = $contentType->getContentTypeGroups();
- $contentTypeInGroup = false;
- foreach ($existingContentTypeGroups as $existingGroup) {
- if ($existingGroup->id == $contentTypeGroup->id) {
- $contentTypeInGroup = true;
- break;
- }
- }
-
- if (!$contentTypeInGroup) {
- throw new Exceptions\NotFoundException('The content type is not in the provided group');
- }
-
- if (count($existingContentTypeGroups) == 1) {
- throw new ForbiddenException('Cannot unlink the content type from its only remaining group');
- }
-
- $this->contentTypeService->unassignContentTypeGroup(
- $contentType,
- $contentTypeGroup
- );
-
- $contentType = $this->contentTypeService->loadContentType($contentTypeId);
-
- return new Values\ContentTypeGroupRefList(
- $contentType,
- $contentType->getContentTypeGroups()
- );
- }
-
- /**
- * Converts the provided ContentTypeGroupCreateStruct to ContentTypeGroupUpdateStruct.
- *
- * @param \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroupCreateStruct $createStruct
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroupUpdateStruct
- */
- private function mapToGroupUpdateStruct(ContentTypeGroupCreateStruct $createStruct)
- {
- return new ContentTypeGroupUpdateStruct(
- [
- 'identifier' => $createStruct->identifier,
- 'modifierId' => $createStruct->creatorId,
- 'modificationDate' => $createStruct->creationDate,
- ]
- );
- }
-
- /**
- * @param array &$contentTypes
- * @param string $orderby
- *
- * @return mixed
- *
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
- */
- protected function sortContentTypeList(array &$contentTypes, $orderby, $sort = 'asc')
- {
- switch ($orderby) {
- case 'name':
- if ($sort === 'asc' || $sort === null) {
- usort(
- $contentTypes,
- static function (APIContentType $contentType1, APIContentType $contentType2) {
- return strcasecmp($contentType1->identifier, $contentType2->identifier);
- }
- );
- } elseif ($sort === 'desc') {
- usort(
- $contentTypes,
- static function (APIContentType $contentType1, APIContentType $contentType2) {
- return strcasecmp($contentType1->identifier, $contentType2->identifier) * -1;
- }
- );
- } else {
- throw new BadRequestException('wrong value for sort parameter');
- }
- break;
- case 'lastmodified':
- if ($sort === 'asc' || $sort === null) {
- usort(
- $contentTypes,
- static function ($timeObj3, $timeObj4) {
- $timeObj3 = strtotime($timeObj3->modificationDate->format('Y-m-d H:i:s'));
- $timeObj4 = strtotime($timeObj4->modificationDate->format('Y-m-d H:i:s'));
-
- return $timeObj3 > $timeObj4;
- }
- );
- } elseif ($sort === 'desc') {
- usort(
- $contentTypes,
- static function ($timeObj3, $timeObj4) {
- $timeObj3 = strtotime($timeObj3->modificationDate->format('Y-m-d H:i:s'));
- $timeObj4 = strtotime($timeObj4->modificationDate->format('Y-m-d H:i:s'));
-
- return $timeObj3 < $timeObj4;
- }
- );
- } else {
- throw new BadRequestException('wrong value for sort parameter');
- }
- break;
- default:
- throw new BadRequestException('wrong value for orderby parameter');
- break;
- }
- }
-
- /**
- * @return ContentType[]
- */
- protected function getContentTypeList()
- {
- $contentTypes = [];
- foreach ($this->contentTypeService->loadContentTypeGroups() as $contentTypeGroup) {
- $contentTypes = array_merge(
- $contentTypes,
- $this->contentTypeService->loadContentTypes($contentTypeGroup, Language::ALL)
- );
- }
-
- return $contentTypes;
- }
-}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeCopyController.php b/src/lib/Server/Controller/ContentType/ContentTypeCopyController.php
new file mode 100644
index 000000000..f8d836732
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeCopyController.php
@@ -0,0 +1,44 @@
+contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Copies a content type. The identifier of the copy is changed to
+ * copy_of__ and a new remoteId is generated.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\ResourceCreated
+ */
+ public function copyContentType($contentTypeId)
+ {
+ $copiedContentType = $this->contentTypeService->copyContentType(
+ $this->contentTypeService->loadContentType($contentTypeId)
+ );
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_content_type',
+ ['contentTypeId' => $copiedContentType->id]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeCreateController.php b/src/lib/Server/Controller/ContentType/ContentTypeCreateController.php
new file mode 100644
index 000000000..b370fc4c0
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeCreateController.php
@@ -0,0 +1,183 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new content type draft in the given content type group.',
+ tags: [
+ 'Type Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new content type or draft is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content type Create schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentTypeCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/POST/ContentTypeCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Content type created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentType+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentType',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentType+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition. Validation on a Field definition fails. Validation of the content type fails, e.g. multiple Fields of a same singular Field Type are provided. Publish is set to true and the input is not complete e.g. no Field definitions are provided.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create this content type.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A content type with same identifier already exists.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeCreateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Creates a new content type draft in the given content type group.
+ *
+ * @param $contentTypeGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedContentType
+ */
+ public function createContentType($contentTypeGroupId, Request $request)
+ {
+ $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
+ $publish = ($request->query->has('publish') && $request->query->get('publish') === 'true');
+
+ try {
+ $contentTypeDraft = $this->contentTypeService->createContentType(
+ $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ // @todo Needs refactoring! Temporary solution so parser has access to get parameters
+ '__publish' => $publish,
+ ],
+ $request->getContent()
+ )
+ ),
+ [$contentTypeGroup]
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (ContentTypeValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (ContentTypeFieldDefinitionValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (Exceptions\Parser $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ if ($publish) {
+ $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
+
+ $contentType = $this->contentTypeService->loadContentType($contentTypeDraft->id, Language::ALL);
+
+ return new Values\CreatedContentType(
+ [
+ 'contentType' => new Values\RestContentType(
+ $contentType,
+ $contentType->getFieldDefinitions()->toArray()
+ ),
+ ]
+ );
+ }
+
+ return new Values\CreatedContentType(
+ [
+ 'contentType' => new Values\RestContentType(
+ $contentTypeDraft,
+ $contentTypeDraft->getFieldDefinitions()->toArray()
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDeleteController.php b/src/lib/Server/Controller/ContentType/ContentTypeDeleteController.php
new file mode 100644
index 000000000..f74d35161
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDeleteController.php
@@ -0,0 +1,84 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - content type deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete this content type.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - There are object instances of this content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDeleteController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * The given content type is deleted.
+ *
+ * @param $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteContentType($contentTypeId)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+
+ try {
+ $this->contentTypeService->deleteContentType($contentType);
+ } catch (BadStateException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftCreateController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftCreateController.php
new file mode 100644
index 000000000..966ee29f8
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftCreateController.php
@@ -0,0 +1,167 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a draft and updates it with the given data.',
+ tags: [
+ 'Type',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new content type draft is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content type Update schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentTypeUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Draft created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeInfo+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfo',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeInfo+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create the draft.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A content type with the given new identifier already exists. A draft already exists.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftCreateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Creates a draft and updates it with the given data.
+ *
+ * @param $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedContentType
+ */
+ public function createContentTypeDraft($contentTypeId, Request $request)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+
+ try {
+ $contentTypeDraft = $this->contentTypeService->createContentTypeDraft(
+ $contentType
+ );
+ } catch (BadStateException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ $contentTypeUpdateStruct = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ ],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $this->contentTypeService->updateContentTypeDraft(
+ $contentTypeDraft,
+ $contentTypeUpdateStruct
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\CreatedContentType(
+ [
+ 'contentType' => new Values\RestContentType(
+ // Reload the content type draft to get the updated values
+ $this->contentTypeService->loadContentTypeDraft(
+ $contentTypeDraft->id
+ )
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftDeleteController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftDeleteController.php
new file mode 100644
index 000000000..294e79c23
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftDeleteController.php
@@ -0,0 +1,71 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - content type draft deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete this content type draft.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type draft does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftDeleteController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * The given content type draft is deleted.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteContentTypeDraft($contentTypeId)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ $this->contentTypeService->deleteContentType($contentTypeDraft);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftFeildDefinitionAddController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftFeildDefinitionAddController.php
new file mode 100644
index 000000000..090aaa00d
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftFeildDefinitionAddController.php
@@ -0,0 +1,166 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Field definition for the given content type.',
+ tags: [
+ 'Type',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new Field definition is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Field Definition Create schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.FieldDefinitionCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/POST/FieldDefinitionCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinitionCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionCreateWrapper',
+ ],
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Field definition created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinition+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinition',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinition+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition or validation on the Field definition fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to add a Field definition.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A Field definition with the same identifier already exists in the given content type. The Field definition is of singular type, already existing in the given content type. The Field definition you want to add is of a type that can\'t be added to a content type that already has content instances.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftFeildDefinitionAddController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Creates a new field definition for the given content type draft.
+ *
+ * @param $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedFieldDefinition
+ */
+ public function addContentTypeDraftFieldDefinition($contentTypeId, Request $request)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ $fieldDefinitionCreate = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ ],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $this->contentTypeService->addFieldDefinition(
+ $contentTypeDraft,
+ $fieldDefinitionCreate
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (ContentTypeFieldDefinitionValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (BadStateException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ $updatedDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ foreach ($updatedDraft->getFieldDefinitions() as $fieldDefinition) {
+ if ($fieldDefinition->identifier == $fieldDefinitionCreate->identifier) {
+ return new Values\CreatedFieldDefinition(
+ [
+ 'fieldDefinition' => new Values\RestFieldDefinition($updatedDraft, $fieldDefinition),
+ ]
+ );
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionDeleteController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionDeleteController.php
new file mode 100644
index 000000000..b71dcd60c
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionDeleteController.php
@@ -0,0 +1,99 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'fieldDefinitionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - Field definition deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete this content type.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - There is no draft of the content type assigned to the authenticated user.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftFieldDefinitionDeleteController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Deletes a field definition from a content type draft.
+ *
+ * @param $contentTypeId
+ * @param $fieldDefinitionId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function removeContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+
+ $fieldDefinition = null;
+ foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDef) {
+ if ($fieldDef->id == $fieldDefinitionId) {
+ $fieldDefinition = $fieldDef;
+ }
+ }
+
+ if ($fieldDefinition === null) {
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+
+ $this->contentTypeService->removeFieldDefinition(
+ $contentTypeDraft,
+ $fieldDefinition
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionListController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionListController.php
new file mode 100644
index 000000000..586a2616f
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionListController.php
@@ -0,0 +1,91 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - return a list of Field definitions.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinitionList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitions',
+ ],
+ ],
+ 'application/vnd.ibexa.api.FieldDefinitionList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionsWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type draft does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftFieldDefinitionListController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Loads field definitions for a given content type draft.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
+ */
+ public function loadContentTypeDraftFieldDefinitionList($contentTypeId)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+
+ return new Values\FieldDefinitionList(
+ $contentTypeDraft,
+ $contentTypeDraft->getFieldDefinitions()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionLoadByIdController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionLoadByIdController.php
new file mode 100644
index 000000000..1a214aa05
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionLoadByIdController.php
@@ -0,0 +1,115 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'fieldDefinitionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the Field definition.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinition+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinition',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinition+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read the content type draft.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type or draft does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftFieldDefinitionLoadByIdController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns the draft field definition given by id.
+ *
+ * @param $contentTypeId
+ * @param $fieldDefinitionId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestFieldDefinition
+ */
+ public function loadContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+
+ foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDefinition) {
+ if ($fieldDefinition->id == $fieldDefinitionId) {
+ return new Values\RestFieldDefinition(
+ $contentTypeDraft,
+ $fieldDefinition
+ );
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionUpdateController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionUpdateController.php
new file mode 100644
index 000000000..79ca6eb67
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftFieldDefinitionUpdateController.php
@@ -0,0 +1,178 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates the attributes of a Field definition.',
+ tags: [
+ 'Type',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Field definition is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Field definition update schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'fieldDefinitionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.FieldDefinitionUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/field_definitions/field_definition_id/PATCH/FieldDefinitionUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinitionUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionUpdateWrapper',
+ ],
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - attributes updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinition+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinition',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinition+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to update the Field definition.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A Field definition with the given identifier already exists in the given content type.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftFieldDefinitionUpdateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Updates the attributes of a field definition.
+ *
+ * @param $contentTypeId
+ * @param $fieldDefinitionId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
+ */
+ public function updateContentTypeDraftFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ $fieldDefinitionUpdate = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ // @todo Needs refactoring! Temporary solution so parser has access to URL
+ 'Url' => $request->getPathInfo(),
+ ],
+ $request->getContent()
+ )
+ );
+
+ $fieldDefinition = null;
+ foreach ($contentTypeDraft->getFieldDefinitions() as $fieldDef) {
+ if ($fieldDef->id == $fieldDefinitionId) {
+ $fieldDefinition = $fieldDef;
+ }
+ }
+
+ if ($fieldDefinition === null) {
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+
+ try {
+ $this->contentTypeService->updateFieldDefinition(
+ $contentTypeDraft,
+ $fieldDefinition,
+ $fieldDefinitionUpdate
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ $updatedDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ foreach ($updatedDraft->getFieldDefinitions() as $fieldDef) {
+ if ($fieldDef->id == $fieldDefinitionId) {
+ return new Values\RestFieldDefinition($updatedDraft, $fieldDef);
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftLoadController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftLoadController.php
new file mode 100644
index 000000000..c1a1f77a4
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftLoadController.php
@@ -0,0 +1,96 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the content type.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentType+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentType',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentType+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist or does not have a draft.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftLoadController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Loads a content type draft.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContentType
+ */
+ public function loadContentTypeDraft($contentTypeId)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+
+ return new Values\RestContentType(
+ $contentTypeDraft,
+ $contentTypeDraft->getFieldDefinitions()->toArray()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftPublishController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftPublishController.php
new file mode 100644
index 000000000..7c6aee72a
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftPublishController.php
@@ -0,0 +1,52 @@
+contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Publishes a content type draft.
+ *
+ * @param $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContentType
+ */
+ public function publishContentTypeDraft($contentTypeId)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+
+ $fieldDefinitions = $contentTypeDraft->getFieldDefinitions();
+ if (empty($fieldDefinitions)) {
+ throw new ForbiddenException('Cannot publish an empty content type draft');
+ }
+
+ $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);
+
+ $publishedContentType = $this->contentTypeService->loadContentType($contentTypeDraft->id, Language::ALL);
+
+ return new Values\RestContentType(
+ $publishedContentType,
+ $publishedContentType->getFieldDefinitions()->toArray()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeDraftUpdateController.php b/src/lib/Server/Controller/ContentType/ContentTypeDraftUpdateController.php
new file mode 100644
index 000000000..7c4d59275
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeDraftUpdateController.php
@@ -0,0 +1,156 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates metadata of a draft. This method does not handle Field definitions. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Type',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new content type draft is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content type update schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentTypeUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'Draft metadata updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeInfo+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfo',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeInfo+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PATCH/ContentTypeInfo.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to update the draft.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A content type with the given new identifier already exists.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - There is no draft for this content type.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeDraftUpdateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Updates meta data of a draft. This method does not handle field definitions.
+ *
+ * @param $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContentType
+ */
+ public function updateContentTypeDraft($contentTypeId, Request $request)
+ {
+ $contentTypeDraft = $this->contentTypeService->loadContentTypeDraft($contentTypeId);
+ $contentTypeUpdateStruct = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ ],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $this->contentTypeService->updateContentTypeDraft(
+ $contentTypeDraft,
+ $contentTypeUpdateStruct
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\RestContentType(
+ // Reload the content type draft to get the updated values
+ $this->contentTypeService->loadContentTypeDraft(
+ $contentTypeDraft->id
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionListController.php b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionListController.php
new file mode 100644
index 000000000..ad8da4bfa
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionListController.php
@@ -0,0 +1,94 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - return a list of Field definitions.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinitionList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitions',
+ ],
+ ],
+ 'application/vnd.ibexa.api.FieldDefinitionList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionsWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeFieldDefinitionListController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Loads field definitions for a given content type.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\FieldDefinitionList
+ *
+ * @todo Check why this isn't in the specs
+ */
+ public function loadContentTypeFieldDefinitionList($contentTypeId)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
+
+ return new Values\FieldDefinitionList(
+ $contentType,
+ $contentType->getFieldDefinitions()->toArray()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdController.php b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdController.php
new file mode 100644
index 000000000..6d9d24b3c
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdController.php
@@ -0,0 +1,116 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'fieldDefinitionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the Field definition.',
+ 'content' => [
+ 'application/vnd.ibexa.api.FieldDefinition+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinition',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.xml.example',
+ ],
+ 'application/vnd.ibexa.api.FieldDefinition+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/FieldDefinitionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/field_definition_id/GET/FieldDefinition.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read the content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeFieldDefinitionLoadByIdController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns the field definition given by id.
+ *
+ * @param $contentTypeId
+ * @param $fieldDefinitionId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestFieldDefinition
+ */
+ public function loadContentTypeFieldDefinition($contentTypeId, $fieldDefinitionId, Request $request)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
+
+ foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
+ if ($fieldDefinition->id == $fieldDefinitionId) {
+ return new Values\RestFieldDefinition(
+ $contentType,
+ $fieldDefinition
+ );
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdentifierController.php b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdentifierController.php
new file mode 100644
index 000000000..e851f9dc3
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeFieldDefinitionLoadByIdentifierController.php
@@ -0,0 +1,56 @@
+contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ */
+ public function loadContentTypeFieldDefinitionByIdentifier(
+ int $contentTypeId,
+ string $fieldDefinitionIdentifier,
+ Request $request
+ ): Values\RestFieldDefinition {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+ $fieldDefinition = $contentType->getFieldDefinition($fieldDefinitionIdentifier);
+ $path = $this->router->generate(
+ 'ibexa.rest.load_content_type_field_definition_by_identifier',
+ [
+ 'contentTypeId' => $contentType->id,
+ 'fieldDefinitionIdentifier' => $fieldDefinitionIdentifier,
+ ]
+ );
+
+ if ($fieldDefinition === null) {
+ throw new Exceptions\NotFoundException(
+ sprintf("Field definition not found: '%s'.", $request->getPathInfo())
+ );
+ }
+
+ return new Values\RestFieldDefinition(
+ $contentType,
+ $fieldDefinition,
+ $path
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupCreateController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupCreateController.php
new file mode 100644
index 000000000..f8cba878a
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupCreateController.php
@@ -0,0 +1,133 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new content type group.',
+ tags: [
+ 'Type Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new content type group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content type group input schema encoded in XML or JSON.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentTypeGroupInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Content type group created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create this content type group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A content type group with the same identifier already exists.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupCreateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Creates a new content type group.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedContentTypeGroup
+ */
+ public function createContentTypeGroup(Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ return new Values\CreatedContentTypeGroup(
+ [
+ 'contentTypeGroup' => $this->contentTypeService->createContentTypeGroup($createStruct),
+ ]
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupDeleteController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupDeleteController.php
new file mode 100644
index 000000000..55108487e
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupDeleteController.php
@@ -0,0 +1,83 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - content type group deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete this content type group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - The content type group is not empty.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type group does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupDeleteController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * The given content type group is deleted.
+ *
+ * @param mixed $contentTypeGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteContentTypeGroup($contentTypeGroupId)
+ {
+ $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
+
+ $contentTypes = $this->contentTypeService->loadContentTypes($contentTypeGroup);
+ if (!empty($contentTypes)) {
+ throw new ForbiddenException('Only empty content type groups can be deleted');
+ }
+
+ $this->contentTypeService->deleteContentTypeGroup($contentTypeGroup);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupListController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupListController.php
new file mode 100644
index 000000000..ace3a7949
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupListController.php
@@ -0,0 +1,96 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupListController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns the content type groups the content type belongs to.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
+ */
+ public function loadGroupsOfContentType($contentTypeId)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
+
+ return new Values\ContentTypeGroupRefList(
+ $contentType,
+ $contentType->getContentTypeGroups()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupLoadByIdController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupLoadByIdController.php
new file mode 100644
index 000000000..9936d9461
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupLoadByIdController.php
@@ -0,0 +1,100 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the content type group.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this content type group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type group does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupLoadByIdController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns the content type group given by id.
+ *
+ * @param $contentTypeGroupId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup
+ */
+ public function loadContentTypeGroup($contentTypeGroupId)
+ {
+ return $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL);
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupUpdateController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupUpdateController.php
new file mode 100644
index 000000000..5f53c6f99
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupUpdateController.php
@@ -0,0 +1,176 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a content type group. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Type Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated content type group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content type group input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag causes patching only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentTypeGroupInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroupInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'Content type group updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/POST/ContentTypeGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/PATCH/ContentTypeGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create this content type group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A content type group with the given identifier already exists.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - The current ETag does not match the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupUpdateController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Updates a content type group.
+ *
+ * @param $contentTypeGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup
+ */
+ public function updateContentTypeGroup($contentTypeGroupId, Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $this->contentTypeService->updateContentTypeGroup(
+ $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId),
+ $this->mapToGroupUpdateStruct($createStruct)
+ );
+
+ return $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL);
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+
+ /**
+ * Converts the provided ContentTypeGroupCreateStruct to ContentTypeGroupUpdateStruct.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroupCreateStruct $createStruct
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroupUpdateStruct
+ */
+ private function mapToGroupUpdateStruct(ContentTypeGroupCreateStruct $createStruct)
+ {
+ return new ContentTypeGroupUpdateStruct(
+ [
+ 'identifier' => $createStruct->identifier,
+ 'modifierId' => $createStruct->creatorId,
+ 'modificationDate' => $createStruct->creationDate,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeGroupsListController.php b/src/lib/Server/Controller/ContentType/ContentTypeGroupsListController.php
new file mode 100644
index 000000000..d887c4a87
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeGroupsListController.php
@@ -0,0 +1,103 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list of content type groups.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroupList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/GET/ContentTypeGroupList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_TEMPORARY_REDIRECT => [
+ 'description' => 'Temporary redirect.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read content types.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type group with the given identifier does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeGroupsListController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns a list of all content type groups.
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeGroupList
+ */
+ public function loadContentTypeGroupList(Request $request)
+ {
+ if ($request->query->has('identifier')) {
+ $contentTypeGroup = $this->contentTypeService->loadContentTypeGroupByIdentifier(
+ $request->query->get('identifier')
+ );
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate(
+ 'ibexa.rest.load_content_type_group',
+ [
+ 'contentTypeGroupId' => $contentTypeGroup->id,
+ ]
+ )
+ );
+ }
+
+ return new Values\ContentTypeGroupList(
+ $this->contentTypeService->loadContentTypeGroups(Language::ALL)
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeLinkToGroupController.php b/src/lib/Server/Controller/ContentType/ContentTypeLinkToGroupController.php
new file mode 100644
index 000000000..489c71747
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeLinkToGroupController.php
@@ -0,0 +1,142 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Links a content type group to the content type and returns the updated group list.',
+ tags: [
+ 'Type',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated content type group list is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to add a group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - The content type is already assigned to the group.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class ContentTypeLinkToGroupController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Links a content type group to the content type and returns the updated group list.
+ *
+ * @param mixed $contentTypeId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
+ */
+ public function linkContentTypeToGroup($contentTypeId, Request $request)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+
+ try {
+ $contentTypeGroupId = $this->requestParser->parseHref(
+ $request->query->get('group'),
+ 'contentTypeGroupId'
+ );
+ } catch (Exceptions\InvalidArgumentException $e) {
+ // Group URI does not match the required value
+ throw new BadRequestException($e->getMessage());
+ }
+
+ $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
+
+ $existingContentTypeGroups = $contentType->getContentTypeGroups();
+ $contentTypeInGroup = false;
+ foreach ($existingContentTypeGroups as $existingGroup) {
+ if ($existingGroup->id == $contentTypeGroup->id) {
+ $contentTypeInGroup = true;
+ break;
+ }
+ }
+
+ if ($contentTypeInGroup) {
+ throw new ForbiddenException('The content type is already linked to the provided group');
+ }
+
+ $this->contentTypeService->assignContentTypeGroup(
+ $contentType,
+ $contentTypeGroup
+ );
+
+ $existingContentTypeGroups[] = $contentTypeGroup;
+
+ return new Values\ContentTypeGroupRefList(
+ $contentType,
+ $existingContentTypeGroups
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeListController.php b/src/lib/Server/Controller/ContentType/ContentTypeListController.php
new file mode 100644
index 000000000..d91faecb7
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeListController.php
@@ -0,0 +1,231 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list of content types.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeInfoList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeInfoList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeList',
+ ],
+ ],
+ 'application/vnd.ibexa.api.ContentTypeList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeListWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read the content types.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeListController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns a list of content types.
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeList|\Ibexa\Rest\Server\Values\ContentTypeInfoList
+ */
+ public function listContentTypes(Request $request)
+ {
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.contenttypelist') {
+ $return = new Values\ContentTypeList([], $request->getPathInfo());
+ } else {
+ $return = new Values\ContentTypeInfoList([], $request->getPathInfo());
+ }
+
+ if ($request->query->has('identifier')) {
+ $return->contentTypes = [$this->loadContentTypeByIdentifier($request)];
+
+ return $return;
+ }
+
+ if ($request->query->has('remoteId')) {
+ $return->contentTypes = [
+ $this->loadContentTypeByRemoteId($request),
+ ];
+
+ return $return;
+ }
+
+ $limit = null;
+ if ($request->query->has('limit')) {
+ $limit = (int)$request->query->get('limit', null);
+ if ($limit <= 0) {
+ throw new BadRequestException('wrong value for limit parameter');
+ }
+ }
+ $contentTypes = $this->getContentTypeList();
+ $sort = $request->query->get('sort');
+ if ($request->query->has('orderby')) {
+ $orderby = $request->query->get('orderby');
+ $this->sortContentTypeList($contentTypes, $orderby, $sort);
+ }
+ $offset = $request->query->get('offset', 0);
+ $return->contentTypes = array_slice($contentTypes, $offset, $limit);
+
+ return $return;
+ }
+
+ /**
+ * Loads a content type by its identifier.
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType
+ */
+ public function loadContentTypeByIdentifier(Request $request)
+ {
+ return $this->contentTypeService->loadContentTypeByIdentifier(
+ $request->query->get('identifier'),
+ Language::ALL
+ );
+ }
+
+ /**
+ * Loads a content type by its remote ID.
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType
+ */
+ public function loadContentTypeByRemoteId(Request $request)
+ {
+ return $this->contentTypeService->loadContentTypeByRemoteId(
+ $request->query->get('remoteId'),
+ Language::ALL
+ );
+ }
+
+ /**
+ * @param array &$contentTypes
+ * @param string $orderby
+ *
+ * @return mixed
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ */
+ protected function sortContentTypeList(array &$contentTypes, $orderby, $sort = 'asc')
+ {
+ switch ($orderby) {
+ case 'name':
+ if ($sort === 'asc' || $sort === null) {
+ usort(
+ $contentTypes,
+ static function (APIContentType $contentType1, APIContentType $contentType2) {
+ return strcasecmp($contentType1->identifier, $contentType2->identifier);
+ }
+ );
+ } elseif ($sort === 'desc') {
+ usort(
+ $contentTypes,
+ static function (APIContentType $contentType1, APIContentType $contentType2) {
+ return strcasecmp($contentType1->identifier, $contentType2->identifier) * -1;
+ }
+ );
+ } else {
+ throw new BadRequestException('wrong value for sort parameter');
+ }
+ break;
+ case 'lastmodified':
+ if ($sort === 'asc' || $sort === null) {
+ usort(
+ $contentTypes,
+ static function ($timeObj3, $timeObj4) {
+ $timeObj3 = strtotime($timeObj3->modificationDate->format('Y-m-d H:i:s'));
+ $timeObj4 = strtotime($timeObj4->modificationDate->format('Y-m-d H:i:s'));
+
+ return $timeObj3 > $timeObj4;
+ }
+ );
+ } elseif ($sort === 'desc') {
+ usort(
+ $contentTypes,
+ static function ($timeObj3, $timeObj4) {
+ $timeObj3 = strtotime($timeObj3->modificationDate->format('Y-m-d H:i:s'));
+ $timeObj4 = strtotime($timeObj4->modificationDate->format('Y-m-d H:i:s'));
+
+ return $timeObj3 < $timeObj4;
+ }
+ );
+ } else {
+ throw new BadRequestException('wrong value for sort parameter');
+ }
+ break;
+ default:
+ throw new BadRequestException('wrong value for orderby parameter');
+ break;
+ }
+ }
+
+ /**
+ * @return ContentType[]
+ */
+ protected function getContentTypeList()
+ {
+ $contentTypes = [];
+ foreach ($this->contentTypeService->loadContentTypeGroups() as $contentTypeGroup) {
+ $contentTypes = array_merge(
+ $contentTypes,
+ $this->contentTypeService->loadContentTypes($contentTypeGroup, Language::ALL)
+ );
+ }
+
+ return $contentTypes;
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeListForGroupController.php b/src/lib/Server/Controller/ContentType/ContentTypeListForGroupController.php
new file mode 100644
index 000000000..06f5ebecd
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeListForGroupController.php
@@ -0,0 +1,111 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list on content types.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeInfoList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/typegroups/content_type_group_id/types/GET/ContentTypeInfoList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeInfoList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeInfoListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read the content types.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeListForGroupController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Returns a list of content types of the group.
+ *
+ * @param string $contentTypeGroupId
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeList|\Ibexa\Rest\Server\Values\ContentTypeInfoList
+ */
+ public function listContentTypesForGroup($contentTypeGroupId, Request $request)
+ {
+ $contentTypes = $this->contentTypeService->loadContentTypes(
+ $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId, Language::ALL),
+ Language::ALL
+ );
+
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.contenttypelist') {
+ return new Values\ContentTypeList($contentTypes, $request->getPathInfo());
+ }
+
+ return new Values\ContentTypeInfoList($contentTypes, $request->getPathInfo());
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeLoadByIdController.php b/src/lib/Server/Controller/ContentType/ContentTypeLoadByIdController.php
new file mode 100644
index 000000000..309c7e608
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeLoadByIdController.php
@@ -0,0 +1,106 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the content type.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentType+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentType',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/draft/PUBLISH/ContentType.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentType+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/GET/ContentType.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content type does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeLoadByIdController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Loads a content type.
+ *
+ * @param $contentTypeId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestContentType
+ */
+ public function loadContentType($contentTypeId)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId, Language::ALL);
+
+ return new Values\RestContentType(
+ $contentType,
+ $contentType->getFieldDefinitions()->toArray()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ContentType/ContentTypeUnlinkFromGroupController.php b/src/lib/Server/Controller/ContentType/ContentTypeUnlinkFromGroupController.php
new file mode 100644
index 000000000..ee70d408e
--- /dev/null
+++ b/src/lib/Server/Controller/ContentType/ContentTypeUnlinkFromGroupController.php
@@ -0,0 +1,137 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentTypeId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentTypeGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentTypeGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/groups/id/DELETE/ContentTypeGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete this content type.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - content type cannot be unlinked from the only remaining group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The resource does not exist.',
+ ],
+ ],
+ ),
+)]
+class ContentTypeUnlinkFromGroupController extends RestController
+{
+ protected ContentTypeService $contentTypeService;
+
+ public function __construct(ContentTypeService $contentTypeService)
+ {
+ $this->contentTypeService = $contentTypeService;
+ }
+
+ /**
+ * Removes the given group from the content type and returns the updated group list.
+ *
+ * @param $contentTypeId
+ * @param $contentTypeGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\ContentTypeGroupRefList
+ */
+ public function unlinkContentTypeFromGroup($contentTypeId, $contentTypeGroupId)
+ {
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+ $contentTypeGroup = $this->contentTypeService->loadContentTypeGroup($contentTypeGroupId);
+
+ $existingContentTypeGroups = $contentType->getContentTypeGroups();
+ $contentTypeInGroup = false;
+ foreach ($existingContentTypeGroups as $existingGroup) {
+ if ($existingGroup->id == $contentTypeGroup->id) {
+ $contentTypeInGroup = true;
+ break;
+ }
+ }
+
+ if (!$contentTypeInGroup) {
+ throw new Exceptions\NotFoundException('The content type is not in the provided group');
+ }
+
+ if (count($existingContentTypeGroups) == 1) {
+ throw new ForbiddenException('Cannot unlink the content type from its only remaining group');
+ }
+
+ $this->contentTypeService->unassignContentTypeGroup(
+ $contentType,
+ $contentTypeGroup
+ );
+
+ $contentType = $this->contentTypeService->loadContentType($contentTypeId);
+
+ return new Values\ContentTypeGroupRefList(
+ $contentType,
+ $contentType->getContentTypeGroups()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/JWT.php b/src/lib/Server/Controller/JWT.php
index f1f705b3b..fabaf68af 100644
--- a/src/lib/Server/Controller/JWT.php
+++ b/src/lib/Server/Controller/JWT.php
@@ -8,9 +8,81 @@
namespace Ibexa\Rest\Server\Controller;
+use ApiPlatform\Metadata\Post;
+use ApiPlatform\OpenApi\Factory\OpenApiFactory;
+use ApiPlatform\OpenApi\Model;
use Ibexa\Rest\Server\Controller as RestController;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+#[Post(
+ uriTemplate: '/user/token/jwt',
+ name: 'Create JWT token',
+ extraProperties: [OpenApiFactory::OVERRIDE_OPENAPI_RESPONSES => false],
+ openapi: new Model\Operation(
+ summary: 'Creates JWT authentication token.',
+ tags: [
+ 'User Token',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the token is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The SessionInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.JWTInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/JWTInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.JWTInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/JWTInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/token/jwt/POST/JWTInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.JWT+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/JWT',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.xml.example',
+ ],
+ 'application/vnd.ibexa.api.JWT+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/JWTWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/token/jwt/POST/JWT.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - Unauthorized',
+ ],
+ ],
+ ),
+)]
final class JWT extends RestController
{
public function createToken(Request $request): void
diff --git a/src/lib/Server/Controller/Language/LanguageListController.php b/src/lib/Server/Controller/Language/LanguageListController.php
new file mode 100644
index 000000000..9373ec053
--- /dev/null
+++ b/src/lib/Server/Controller/Language/LanguageListController.php
@@ -0,0 +1,77 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.LanguageList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LanguageList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/languages/GET/LanguageList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LanguageList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LanguageListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/languages/GET/LanguageList.json.example',
+ ],
+ ],
+ ],
+ ],
+ ),
+)]
+final class LanguageListController extends RestController
+{
+ private LanguageService $languageService;
+
+ public function __construct(LanguageService $languageService)
+ {
+ $this->languageService = $languageService;
+ }
+
+ public function listLanguages(): LanguageList
+ {
+ $languages = $this->languageService->loadLanguages();
+
+ if ($languages instanceof Traversable) {
+ $languages = iterator_to_array($languages);
+ }
+
+ return new LanguageList($languages);
+ }
+}
diff --git a/src/lib/Server/Controller/Language.php b/src/lib/Server/Controller/Language/LanguageLoadByIdController.php
similarity index 56%
rename from src/lib/Server/Controller/Language.php
rename to src/lib/Server/Controller/Language/LanguageLoadByIdController.php
index 882077816..708de672f 100644
--- a/src/lib/Server/Controller/Language.php
+++ b/src/lib/Server/Controller/Language/LanguageLoadByIdController.php
@@ -6,56 +6,15 @@
*/
declare(strict_types=1);
-namespace Ibexa\Rest\Server\Controller;
+namespace Ibexa\Rest\Server\Controller\Language;
use ApiPlatform\Metadata\Get;
use ApiPlatform\OpenApi\Model;
use Ibexa\Contracts\Core\Repository\LanguageService;
use Ibexa\Contracts\Core\Repository\Values\Content\Language as ApiLanguage;
use Ibexa\Rest\Server\Controller as RestController;
-use Ibexa\Rest\Server\Values\LanguageList;
use Symfony\Component\HttpFoundation\Response;
-use Traversable;
-#[Get(
- uriTemplate: '/languages',
- name: 'Language list',
- openapi: new Model\Operation(
- summary: 'Lists languages',
- tags: [
- 'Language',
- ],
- parameters: [
- new Model\Parameter(
- name: 'Accept',
- in: 'header',
- required: true,
- description: 'If set, the list is returned in XML or JSON format.',
- schema: [
- 'type' => 'string',
- ],
- ),
- ],
- responses: [
- Response::HTTP_OK => [
- 'content' => [
- 'application/vnd.ibexa.api.LanguageList+xml' => [
- 'schema' => [
- '$ref' => '#/components/schemas/LanguageList',
- ],
- 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/languages/GET/LanguageList.xml.example',
- ],
- 'application/vnd.ibexa.api.LanguageList+json' => [
- 'schema' => [
- '$ref' => '#/components/schemas/LanguageListWrapper',
- ],
- 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/languages/GET/LanguageList.json.example',
- ],
- ],
- ],
- ],
- ),
-)]
#[Get(
uriTemplate: '/languages/{code}',
name: 'Get language',
@@ -102,7 +61,7 @@
],
),
)]
-final class Language extends RestController
+final class LanguageLoadByIdController extends RestController
{
private LanguageService $languageService;
@@ -111,17 +70,6 @@ public function __construct(LanguageService $languageService)
$this->languageService = $languageService;
}
- public function listLanguages(): LanguageList
- {
- $languages = $this->languageService->loadLanguages();
-
- if ($languages instanceof Traversable) {
- $languages = iterator_to_array($languages);
- }
-
- return new LanguageList($languages);
- }
-
public function loadLanguage(string $languageCode): ApiLanguage
{
return $this->languageService->loadLanguage($languageCode);
diff --git a/src/lib/Server/Controller/Location.php b/src/lib/Server/Controller/Location.php
deleted file mode 100644
index 9eebba161..000000000
--- a/src/lib/Server/Controller/Location.php
+++ /dev/null
@@ -1,516 +0,0 @@
-locationService = $locationService;
- $this->contentService = $contentService;
- $this->trashService = $trashService;
- $this->urlAliasService = $urlAliasService;
- }
-
- /**
- * Loads the location for a given ID (x)or remote ID.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
- *
- * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
- */
- public function redirectLocation(Request $request)
- {
- if ($request->query->has('id')) {
- $location = $this->locationService->loadLocation((int)$request->query->get('id'));
- } elseif ($request->query->has('remoteId')) {
- $location = $this->locationService->loadLocationByRemoteId((string)$request->query->get('remoteId'));
- } elseif ($request->query->has('urlAlias')) {
- $urlAlias = $this->urlAliasService->lookup((string)$request->query->get('urlAlias'));
- $location = $this->locationService->loadLocation($urlAlias->destination);
- } else {
- throw new BadRequestException("At least one of 'id', 'remoteId' or 'urlAlias' parameters is required.");
- }
-
- return new Values\TemporaryRedirect(
- $this->router->generate(
- 'ibexa.rest.load_location',
- [
- 'locationPath' => trim($location->pathString, '/'),
- ]
- )
- );
- }
-
- /**
- * Creates a new location for object with id $contentId.
- *
- * @param mixed $contentId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedLocation
- */
- public function createLocation($contentId, Request $request)
- {
- $locationCreateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $contentInfo = $this->contentService->loadContentInfo($contentId);
-
- try {
- $createdLocation = $this->locationService->createLocation($contentInfo, $locationCreateStruct);
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\CreatedLocation(['restLocation' => new Values\RestLocation($createdLocation, 0)]);
- }
-
- /**
- * Loads a location.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\RestLocation
- */
- public function loadLocation($locationPath)
- {
- $location = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath)
- );
-
- if (trim($location->pathString, '/') != $locationPath) {
- throw new Exceptions\NotFoundException(
- "Could not find a Location with path string $locationPath"
- );
- }
-
- return new Values\CachedValue(
- new Values\RestLocation(
- $location,
- $this->locationService->getLocationChildCount($location)
- ),
- ['locationId' => $location->id]
- );
- }
-
- /**
- * Deletes a location.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteSubtree($locationPath)
- {
- $location = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath)
- );
- $this->locationService->deleteLocation($location);
-
- return new Values\NoContent();
- }
-
- /**
- * Copies a subtree to a new destination.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\ResourceCreated
- */
- public function copySubtree($locationPath, Request $request)
- {
- $location = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath)
- );
-
- $destinationLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath(
- $this->uriParser->getAttributeFromUri(
- $request->headers->get('Destination'),
- 'locationPath'
- )
- )
- );
-
- $newLocation = $this->locationService->copySubtree($location, $destinationLocation);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_location',
- [
- 'locationPath' => trim($newLocation->pathString, '/'),
- ]
- )
- );
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function copy(string $locationPath, Request $request): Values\ResourceCreated
- {
- $locationId = $this->extractLocationIdFromPath($locationPath);
- $location = $this->locationService->loadLocation($locationId);
-
- $destinationLocation = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent(),
- ),
- );
-
- $newLocation = $this->locationService->copySubtree($location, $destinationLocation);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_location',
- [
- 'locationPath' => trim($newLocation->pathString, '/'),
- ],
- )
- );
- }
-
- /**
- * Moves a subtree to a new location.
- *
- * @param string $locationPath
- *
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException if the Destination header cannot be parsed as location or trash
- *
- * @return \Ibexa\Rest\Server\Values\ResourceCreated|\Ibexa\Rest\Server\Values\NoContent
- */
- public function moveSubtree($locationPath, Request $request)
- {
- $locationToMove = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath)
- );
-
- $destinationLocationId = null;
- $destinationHref = $request->headers->get('Destination');
- try {
- // First check to see if the destination is for moving within another subtree
- $destinationLocationId = $this->extractLocationIdFromPath(
- $this->uriParser->getAttributeFromUri($destinationHref, 'locationPath')
- );
-
- // We're moving the subtree
- $destinationLocation = $this->locationService->loadLocation($destinationLocationId);
- $this->locationService->moveSubtree($locationToMove, $destinationLocation);
-
- // Reload the location to get the new position is subtree
- $locationToMove = $this->locationService->loadLocation($locationToMove->id);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_location',
- [
- 'locationPath' => trim($locationToMove->pathString, '/'),
- ]
- )
- );
- } catch (Exceptions\InvalidArgumentException $e) {
- // If parsing of destination fails, let's try to see if destination is trash
- try {
- $route = $this->uriParser->matchUri($destinationHref);
- if (!isset($route['_route']) || $route['_route'] !== 'ibexa.rest.load_trash_items') {
- throw new Exceptions\InvalidArgumentException('');
- }
- // Trash the subtree
- $trashItem = $this->trashService->trash($locationToMove);
-
- if (isset($trashItem)) {
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_trash_item',
- ['trashItemId' => $trashItem->id]
- )
- );
- } else {
- // Only a location has been trashed and not the object
- return new Values\NoContent();
- }
- } catch (Exceptions\InvalidArgumentException $e) {
- // If that fails, the Destination header is not formatted right
- // so just throw the BadRequestException
- throw new BadRequestException("{$destinationHref} is not an acceptable destination");
- }
- }
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function moveLocation(Request $request, string $locationPath): Values\ResourceCreated
- {
- $destinationLocation = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent(),
- ),
- );
-
- $locationToMove = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath),
- );
-
- $this->locationService->moveSubtree($locationToMove, $destinationLocation);
-
- // Reload the location to get a new subtree position
- $locationToMove = $this->locationService->loadLocation($locationToMove->id);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_location',
- [
- 'locationPath' => trim($locationToMove->getPathString(), '/'),
- ],
- ),
- );
- }
-
- /**
- * Swaps a location with another one.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function swapLocation($locationPath, Request $request)
- {
- $locationId = $this->extractLocationIdFromPath($locationPath);
- $location = $this->locationService->loadLocation($locationId);
-
- $destinationLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath(
- $this->uriParser->getAttributeFromUri(
- $request->headers->get('Destination'),
- 'locationPath'
- )
- )
- );
-
- $this->locationService->swapLocation($location, $destinationLocation);
-
- return new Values\NoContent();
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function swap(Request $request, string $locationPath): Values\NoContent
- {
- $locationId = $this->extractLocationIdFromPath($locationPath);
- $location = $this->locationService->loadLocation($locationId);
-
- $destinationLocation = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent(),
- ),
- );
-
- $this->locationService->swapLocation($location, $destinationLocation);
-
- return new Values\NoContent();
- }
-
- /**
- * Loads a location by remote ID.
- *
- * @todo remove, or use in loadLocation with filter
- *
- * @return \Ibexa\Rest\Server\Values\LocationList
- */
- public function loadLocationByRemoteId(Request $request)
- {
- return new Values\LocationList(
- [
- new Values\RestLocation(
- $location = $this->locationService->loadLocationByRemoteId(
- $request->query->get('remoteId')
- ),
- $this->locationService->getLocationChildCount($location)
- ),
- ],
- $request->getPathInfo()
- );
- }
-
- /**
- * Loads all locations for content object.
- *
- * @param mixed $contentId
- *
- * @return \Ibexa\Rest\Server\Values\LocationList
- */
- public function loadLocationsForContent($contentId, Request $request)
- {
- $restLocations = [];
- $contentInfo = $this->contentService->loadContentInfo($contentId);
- foreach ($this->locationService->loadLocations($contentInfo) as $location) {
- $restLocations[] = new Values\RestLocation(
- $location,
- // @todo Remove, and make optional in VO. Not needed for a location list.
- $this->locationService->getLocationChildCount($location)
- );
- }
-
- return new Values\CachedValue(
- new Values\LocationList($restLocations, $request->getPathInfo()),
- ['locationId' => $contentInfo->mainLocationId]
- );
- }
-
- /**
- * Loads child locations of a location.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\LocationList
- */
- public function loadLocationChildren($locationPath, Request $request)
- {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 10;
-
- $restLocations = [];
- $locationId = $this->extractLocationIdFromPath($locationPath);
- $children = $this->locationService->loadLocationChildren(
- $this->locationService->loadLocation($locationId),
- $offset >= 0 ? $offset : 0,
- $limit >= 0 ? $limit : 25
- )->locations;
- foreach ($children as $location) {
- $restLocations[] = new Values\RestLocation(
- $location,
- $this->locationService->getLocationChildCount($location)
- );
- }
-
- return new Values\CachedValue(
- new Values\LocationList($restLocations, $request->getPathInfo()),
- ['locationId' => $locationId]
- );
- }
-
- /**
- * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
- *
- * @param string $path
- *
- * @return mixed
- */
- private function extractLocationIdFromPath($path)
- {
- $pathParts = explode('/', $path);
-
- return array_pop($pathParts);
- }
-
- /**
- * Updates a location.
- *
- * @param string $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\RestLocation
- */
- public function updateLocation($locationPath, Request $request)
- {
- $locationUpdate = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $location = $this->locationService->loadLocation($this->extractLocationIdFromPath($locationPath));
-
- // First handle hiding/unhiding so that updating location afterwards
- // will return updated location with hidden/visible status correctly updated
- // Exact check for true/false is needed as null signals that no hiding/unhiding
- // is to be performed
- if ($locationUpdate->hidden === true) {
- $this->locationService->hideLocation($location);
- } elseif ($locationUpdate->hidden === false) {
- $this->locationService->unhideLocation($location);
- }
-
- return new Values\RestLocation(
- $location = $this->locationService->updateLocation($location, $locationUpdate->locationUpdateStruct),
- $this->locationService->getLocationChildCount($location)
- );
- }
-}
diff --git a/src/lib/Server/Controller/Location/LocationBaseController.php b/src/lib/Server/Controller/Location/LocationBaseController.php
new file mode 100644
index 000000000..09088f504
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationBaseController.php
@@ -0,0 +1,75 @@
+locationService = $locationService;
+ $this->contentService = $contentService;
+ $this->trashService = $trashService;
+ $this->urlAliasService = $urlAliasService;
+ }
+
+ /**
+ * Loads a location by remote ID.
+ *
+ * @todo remove, or use in loadLocation with filter
+ *
+ * @return \Ibexa\Rest\Server\Values\LocationList
+ */
+ public function loadLocationByRemoteId(Request $request)
+ {
+ return new Values\LocationList(
+ [
+ new Values\RestLocation(
+ $location = $this->locationService->loadLocationByRemoteId(
+ $request->query->get('remoteId')
+ ),
+ $this->locationService->getLocationChildCount($location)
+ ),
+ ],
+ $request->getPathInfo()
+ );
+ }
+
+ /**
+ * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
+ *
+ * @param string $path
+ *
+ * @return mixed
+ */
+ protected function extractLocationIdFromPath($path)
+ {
+ $pathParts = explode('/', $path);
+
+ return array_pop($pathParts);
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationChildrenListController.php b/src/lib/Server/Controller/Location/LocationChildrenListController.php
new file mode 100644
index 000000000..00dd20b0d
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationChildrenListController.php
@@ -0,0 +1,101 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.LocationList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LocationList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationListWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item with the given ID does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationChildrenListController extends LocationBaseController
+{
+ /**
+ * Loads child locations of a location.
+ *
+ * @param string $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\LocationList
+ */
+ public function loadLocationChildren($locationPath, Request $request)
+ {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 10;
+
+ $restLocations = [];
+ $locationId = $this->extractLocationIdFromPath($locationPath);
+ $children = $this->locationService->loadLocationChildren(
+ $this->locationService->loadLocation($locationId),
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : 25
+ )->locations;
+ foreach ($children as $location) {
+ $restLocations[] = new Values\RestLocation(
+ $location,
+ $this->locationService->getLocationChildCount($location)
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\LocationList($restLocations, $request->getPathInfo()),
+ ['locationId' => $locationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationCreateController.php b/src/lib/Server/Controller/Location/LocationCreateController.php
new file mode 100644
index 000000000..006714636
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationCreateController.php
@@ -0,0 +1,133 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Location for the given content item.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new Location is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The LocationCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.LocationCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LocationCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/LocationCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Location+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Location',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Location+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this Location.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - a Location under the given parent ID already exists.',
+ ],
+ ],
+ ),
+)]
+class LocationCreateController extends LocationBaseController
+{
+ /**
+ * Creates a new location for object with id $contentId.
+ *
+ * @param mixed $contentId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedLocation
+ */
+ public function createLocation($contentId, Request $request)
+ {
+ $locationCreateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $contentInfo = $this->contentService->loadContentInfo($contentId);
+
+ try {
+ $createdLocation = $this->locationService->createLocation($contentInfo, $locationCreateStruct);
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\CreatedLocation(['restLocation' => new Values\RestLocation($createdLocation, 0)]);
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationForContentListController.php b/src/lib/Server/Controller/Location/LocationForContentListController.php
new file mode 100644
index 000000000..577d37a86
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationForContentListController.php
@@ -0,0 +1,104 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.LocationList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LocationList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/GET/LocationList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this content item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the content item with the given ID does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationForContentListController extends LocationBaseController
+{
+ /**
+ * Loads all locations for content object.
+ *
+ * @param mixed $contentId
+ *
+ * @return \Ibexa\Rest\Server\Values\LocationList
+ */
+ public function loadLocationsForContent($contentId, Request $request)
+ {
+ $restLocations = [];
+ $contentInfo = $this->contentService->loadContentInfo($contentId);
+ foreach ($this->locationService->loadLocations($contentInfo) as $location) {
+ $restLocations[] = new Values\RestLocation(
+ $location,
+ // @todo Remove, and make optional in VO. Not needed for a location list.
+ $this->locationService->getLocationChildCount($location)
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\LocationList($restLocations, $request->getPathInfo()),
+ ['locationId' => $contentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationLoadByPathController.php b/src/lib/Server/Controller/Location/LocationLoadByPathController.php
new file mode 100644
index 000000000..bee862cbd
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationLoadByPathController.php
@@ -0,0 +1,107 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Location+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Location',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Location+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to read this Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Location with the given path does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationLoadByPathController extends LocationBaseController
+{
+ /**
+ * Loads a location.
+ *
+ * @param string $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\RestLocation
+ */
+ public function loadLocation($locationPath)
+ {
+ $location = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath)
+ );
+
+ if (trim($location->pathString, '/') != $locationPath) {
+ throw new Exceptions\NotFoundException(
+ "Could not find a Location with path string $locationPath"
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\RestLocation(
+ $location,
+ $this->locationService->getLocationChildCount($location)
+ ),
+ ['locationId' => $location->id]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationRedirectController.php b/src/lib/Server/Controller/Location/LocationRedirectController.php
new file mode 100644
index 000000000..72af79adf
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationRedirectController.php
@@ -0,0 +1,92 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.LocationList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Location',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LocationList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_TEMPORARY_REDIRECT => [
+ 'description' => 'Temporary redirect to the main resource URL.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Location with the given ID (remote ID or URL Alias) does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationRedirectController extends LocationBaseController
+{
+ /**
+ * Loads the location for a given ID (x)or remote ID.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException
+ *
+ * @return \Ibexa\Rest\Server\Values\TemporaryRedirect
+ */
+ public function redirectLocation(Request $request)
+ {
+ if ($request->query->has('id')) {
+ $location = $this->locationService->loadLocation($request->query->get('id'));
+ } elseif ($request->query->has('remoteId')) {
+ $location = $this->locationService->loadLocationByRemoteId($request->query->get('remoteId'));
+ } elseif ($request->query->has('urlAlias')) {
+ $urlAlias = $this->urlAliasService->lookup($request->query->get('urlAlias'));
+ $location = $this->locationService->loadLocation($urlAlias->destination);
+ } else {
+ throw new BadRequestException("At least one of 'id', 'remoteId' or 'urlAlias' parameters is required.");
+ }
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate(
+ 'ibexa.rest.load_location',
+ [
+ 'locationPath' => trim($location->pathString, '/'),
+ ]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationSubtreeCopyController.php b/src/lib/Server/Controller/Location/LocationSubtreeCopyController.php
new file mode 100644
index 000000000..8bac77905
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationSubtreeCopyController.php
@@ -0,0 +1,77 @@
+extractLocationIdFromPath($locationPath);
+ $location = $this->locationService->loadLocation($locationId);
+
+ $destinationLocation = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent(),
+ ),
+ );
+
+ $newLocation = $this->locationService->copySubtree($location, $destinationLocation);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_location',
+ [
+ 'locationPath' => trim($newLocation->pathString, '/'),
+ ],
+ )
+ );
+ }
+
+ /**
+ * Copies a subtree to a new destination.
+ *
+ * @param string $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\ResourceCreated
+ */
+ public function copySubtree($locationPath, Request $request)
+ {
+ $location = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath)
+ );
+
+ $destinationLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath(
+ $this->requestParser->parseHref(
+ $request->headers->get('Destination'),
+ 'locationPath'
+ )
+ )
+ );
+
+ $newLocation = $this->locationService->copySubtree($location, $destinationLocation);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_location',
+ [
+ 'locationPath' => trim($newLocation->pathString, '/'),
+ ]
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationSubtreeDeleteController.php b/src/lib/Server/Controller/Location/LocationSubtreeDeleteController.php
new file mode 100644
index 000000000..d4211a083
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationSubtreeDeleteController.php
@@ -0,0 +1,64 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this subtree.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Location with the given ID does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationSubtreeDeleteController extends LocationBaseController
+{
+ /**
+ * Deletes a location.
+ *
+ * @param string $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteSubtree($locationPath)
+ {
+ $location = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath)
+ );
+ $this->locationService->deleteLocation($location);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationSubtreeMoveController.php b/src/lib/Server/Controller/Location/LocationSubtreeMoveController.php
new file mode 100644
index 000000000..4baa21805
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationSubtreeMoveController.php
@@ -0,0 +1,118 @@
+locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath)
+ );
+
+ $destinationLocationId = null;
+ $destinationHref = $request->headers->get('Destination');
+ try {
+ // First check to see if the destination is for moving within another subtree
+ $destinationLocationId = $this->extractLocationIdFromPath(
+ $this->requestParser->parseHref($destinationHref, 'locationPath')
+ );
+
+ // We're moving the subtree
+ $destinationLocation = $this->locationService->loadLocation($destinationLocationId);
+ $this->locationService->moveSubtree($locationToMove, $destinationLocation);
+
+ // Reload the location to get the new position is subtree
+ $locationToMove = $this->locationService->loadLocation($locationToMove->id);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_location',
+ [
+ 'locationPath' => trim($locationToMove->pathString, '/'),
+ ]
+ )
+ );
+ } catch (Exceptions\InvalidArgumentException $e) {
+ // If parsing of destination fails, let's try to see if destination is trash
+ try {
+ $route = $this->requestParser->parse($destinationHref);
+ if (!isset($route['_route']) || $route['_route'] !== 'ibexa.rest.load_trash_items') {
+ throw new Exceptions\InvalidArgumentException('');
+ }
+ // Trash the subtree
+ $trashItem = $this->trashService->trash($locationToMove);
+
+ if (isset($trashItem)) {
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_trash_item',
+ ['trashItemId' => $trashItem->id]
+ )
+ );
+ } else {
+ // Only a location has been trashed and not the object
+ return new Values\NoContent();
+ }
+ } catch (Exceptions\InvalidArgumentException $e) {
+ // If that fails, the Destination header is not formatted right
+ // so just throw the BadRequestException
+ throw new BadRequestException("{$destinationHref} is not an acceptable destination");
+ }
+ }
+ }
+
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ */
+ public function moveLocation(Request $request, string $locationPath): Values\ResourceCreated
+ {
+ $destinationLocation = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent(),
+ ),
+ );
+
+ $locationToMove = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath),
+ );
+
+ $this->locationService->moveSubtree($locationToMove, $destinationLocation);
+
+ // Reload the location to get a new subtree position
+ $locationToMove = $this->locationService->loadLocation($locationToMove->id);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_location',
+ [
+ 'locationPath' => trim($locationToMove->getPathString(), '/'),
+ ],
+ ),
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationSwapController.php b/src/lib/Server/Controller/Location/LocationSwapController.php
new file mode 100644
index 000000000..514245ff1
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationSwapController.php
@@ -0,0 +1,62 @@
+extractLocationIdFromPath($locationPath);
+ $location = $this->locationService->loadLocation($locationId);
+
+ $destinationLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath(
+ $this->requestParser->parseHref(
+ $request->headers->get('Destination'),
+ 'locationPath'
+ )
+ )
+ );
+
+ $this->locationService->swapLocation($location, $destinationLocation);
+
+ return new Values\NoContent();
+ }
+
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ */
+ public function swap(Request $request, string $locationPath): Values\NoContent
+ {
+ $locationId = $this->extractLocationIdFromPath($locationPath);
+ $location = $this->locationService->loadLocation($locationId);
+
+ $destinationLocation = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent(),
+ ),
+ );
+
+ $this->locationService->swapLocation($location, $destinationLocation);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Location/LocationUpdateController.php b/src/lib/Server/Controller/Location/LocationUpdateController.php
new file mode 100644
index 000000000..66e7659c7
--- /dev/null
+++ b/src/lib/Server/Controller/Location/LocationUpdateController.php
@@ -0,0 +1,141 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates the Location. This method can also be used to hide/reveal a Location via the hidden field in the LocationUpdate. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Location',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the Location is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The LocationUpdate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.LocationUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationUpdateStruct',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.LocationUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationUpdateStructWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/locations/location_id/PATCH/LocationUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Location+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Location',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Location+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/LocationWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/locations/POST/Location.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update this Location.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Location with the given ID does not exist.',
+ ],
+ ],
+ ),
+)]
+class LocationUpdateController extends LocationBaseController
+{
+ /**
+ * Updates a location.
+ *
+ * @param string $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\RestLocation
+ */
+ public function updateLocation($locationPath, Request $request)
+ {
+ $locationUpdate = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $location = $this->locationService->loadLocation($this->extractLocationIdFromPath($locationPath));
+
+ // First handle hiding/unhiding so that updating location afterwards
+ // will return updated location with hidden/visible status correctly updated
+ // Exact check for true/false is needed as null signals that no hiding/unhiding
+ // is to be performed
+ if ($locationUpdate->hidden === true) {
+ $this->locationService->hideLocation($location);
+ } elseif ($locationUpdate->hidden === false) {
+ $this->locationService->unhideLocation($location);
+ }
+
+ return new Values\RestLocation(
+ $location = $this->locationService->updateLocation($location, $locationUpdate->locationUpdateStruct),
+ $this->locationService->getLocationChildCount($location)
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState.php b/src/lib/Server/Controller/ObjectState.php
deleted file mode 100644
index 9f6ab55f1..000000000
--- a/src/lib/Server/Controller/ObjectState.php
+++ /dev/null
@@ -1,344 +0,0 @@
-objectStateService = $objectStateService;
- $this->contentService = $contentService;
- }
-
- /**
- * Creates a new object state group.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedObjectStateGroup
- */
- public function createObjectStateGroup(Request $request)
- {
- try {
- $createdStateGroup = $this->objectStateService->createObjectStateGroup(
- $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- )
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */$e->getMessage());
- }
-
- return new Values\CreatedObjectStateGroup(
- [
- 'objectStateGroup' => $createdStateGroup,
- ]
- );
- }
-
- /**
- * Creates a new object state.
- *
- * @param $objectStateGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedObjectState
- */
- public function createObjectState($objectStateGroupId, Request $request)
- {
- $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
-
- try {
- $createdObjectState = $this->objectStateService->createObjectState(
- $objectStateGroup,
- $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- )
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\CreatedObjectState(
- [
- 'objectState' => new RestObjectState(
- $createdObjectState,
- $objectStateGroup->id
- ),
- ]
- );
- }
-
- /**
- * Loads an object state group.
- *
- * @param $objectStateGroupId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ObjectState\ObjectStateGroup
- */
- public function loadObjectStateGroup($objectStateGroupId)
- {
- return $this->objectStateService->loadObjectStateGroup($objectStateGroupId, Language::ALL);
- }
-
- /**
- * Loads an object state.
- *
- * @param $objectStateGroupId
- * @param $objectStateId
- *
- * @return \Ibexa\Rest\Values\RestObjectState
- */
- public function loadObjectState($objectStateGroupId, $objectStateId)
- {
- return new RestObjectState(
- $this->objectStateService->loadObjectState($objectStateId, Language::ALL),
- $objectStateGroupId
- );
- }
-
- /**
- * Returns a list of all object state groups.
- *
- * @return \Ibexa\Rest\Server\Values\ObjectStateGroupList
- */
- public function loadObjectStateGroups()
- {
- return new Values\ObjectStateGroupList(
- $this->objectStateService->loadObjectStateGroups(0, -1, Language::ALL)
- );
- }
-
- /**
- * Returns a list of all object states of the given group.
- *
- * @param $objectStateGroupId
- *
- * @return \Ibexa\Rest\Server\Values\ObjectStateList
- */
- public function loadObjectStates($objectStateGroupId)
- {
- $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
-
- return new Values\ObjectStateList(
- $this->objectStateService->loadObjectStates($objectStateGroup, Language::ALL),
- $objectStateGroup->id
- );
- }
-
- /**
- * The given object state group including the object states is deleted.
- *
- * @param $objectStateGroupId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteObjectStateGroup($objectStateGroupId)
- {
- $this->objectStateService->deleteObjectStateGroup(
- $this->objectStateService->loadObjectStateGroup($objectStateGroupId)
- );
-
- return new Values\NoContent();
- }
-
- /**
- * The given object state is deleted.
- *
- * @param $objectStateId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteObjectState($objectStateId)
- {
- $this->objectStateService->deleteObjectState(
- $this->objectStateService->loadObjectState($objectStateId)
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Updates an object state group.
- *
- * @param $objectStateGroupId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\ObjectState\ObjectStateGroup
- */
- public function updateObjectStateGroup($objectStateGroupId, Request $request)
- {
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
-
- try {
- $updatedStateGroup = $this->objectStateService->updateObjectStateGroup($objectStateGroup, $updateStruct);
-
- return $updatedStateGroup;
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- /**
- * Updates an object state.
- *
- * @param $objectStateGroupId
- * @param $objectStateId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Values\RestObjectState
- */
- public function updateObjectState($objectStateGroupId, $objectStateId, Request $request)
- {
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $objectState = $this->objectStateService->loadObjectState($objectStateId);
-
- try {
- $updatedObjectState = $this->objectStateService->updateObjectState($objectState, $updateStruct);
-
- return new RestObjectState($updatedObjectState, $objectStateGroupId);
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- /**
- * Returns the object states of content.
- *
- * @param $contentId
- *
- * @return \Ibexa\Rest\Values\ContentObjectStates
- */
- public function getObjectStatesForContent($contentId)
- {
- $groups = $this->objectStateService->loadObjectStateGroups();
- $contentInfo = $this->contentService->loadContentInfo($contentId);
-
- $contentObjectStates = [];
-
- foreach ($groups as $group) {
- try {
- $state = $this->objectStateService->getContentState($contentInfo, $group);
- $contentObjectStates[] = new RestObjectState($state, $group->id);
- } catch (NotFoundException $e) {
- // Do nothing
- }
- }
-
- return new ContentObjectStates($contentObjectStates);
- }
-
- /**
- * Updates object states of content
- * An object state in the input overrides the state of the object state group.
- *
- * @param $contentId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Values\ContentObjectStates
- */
- public function setObjectStatesForContent($contentId, Request $request)
- {
- $newObjectStates = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $countByGroups = [];
- foreach ($newObjectStates as $newObjectState) {
- $groupId = (int)$newObjectState->groupId;
- if (array_key_exists($groupId, $countByGroups)) {
- ++$countByGroups[$groupId];
- } else {
- $countByGroups[$groupId] = 1;
- }
- }
-
- foreach ($countByGroups as $groupId => $count) {
- if ($count > 1) {
- throw new ForbiddenException(
- /** @Ignore */
- "Multiple Object states provided for group with ID $groupId"
- );
- }
- }
-
- $contentInfo = $this->contentService->loadContentInfo($contentId);
-
- $contentObjectStates = [];
- foreach ($newObjectStates as $newObjectState) {
- $objectStateGroup = $this->objectStateService->loadObjectStateGroup($newObjectState->groupId);
- $this->objectStateService->setContentState($contentInfo, $objectStateGroup, $newObjectState->objectState);
- $contentObjectStates[(int)$objectStateGroup->id] = $newObjectState;
- }
-
- return new ContentObjectStates($contentObjectStates);
- }
-}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateCreateController.php b/src/lib/Server/Controller/ObjectState/ObjectStateCreateController.php
new file mode 100644
index 000000000..cdfb009a4
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateCreateController.php
@@ -0,0 +1,156 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Object state.',
+ tags: [
+ 'Object State Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new Object state is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Object state input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ObjectStateCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/POST/ObjectStateCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Object state created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectState+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectState',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectState+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create an Object state.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - An Object state with the same identifier already exists in the given group.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateCreateController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Creates a new object state.
+ *
+ * @param $objectStateGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedObjectState
+ */
+ public function createObjectState($objectStateGroupId, Request $request)
+ {
+ $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
+
+ try {
+ $createdObjectState = $this->objectStateService->createObjectState(
+ $objectStateGroup,
+ $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ )
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\CreatedObjectState(
+ [
+ 'objectState' => new RestObjectState(
+ $createdObjectState,
+ $objectStateGroup->id
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateDeleteController.php b/src/lib/Server/Controller/ObjectState/ObjectStateDeleteController.php
new file mode 100644
index 000000000..3692ec3ca
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateDeleteController.php
@@ -0,0 +1,84 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - Object state deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete an Object state.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The Object state does not exist.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateDeleteController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * The given object state is deleted.
+ *
+ * @param $objectStateId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteObjectState($objectStateId)
+ {
+ $this->objectStateService->deleteObjectState(
+ $this->objectStateService->loadObjectState($objectStateId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateGroupCreateController.php b/src/lib/Server/Controller/ObjectState/ObjectStateGroupCreateController.php
new file mode 100644
index 000000000..270a45f11
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateGroupCreateController.php
@@ -0,0 +1,139 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Object state group.',
+ tags: [
+ 'Object State Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new Object state group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Object state group input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ObjectStateGroupCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroupCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/POST/ObjectStateGroupCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Object state group created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectStateGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create an Object state group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - An Object state group with the same identifier already exists.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateGroupCreateController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Creates a new object state group.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedObjectStateGroup
+ */
+ public function createObjectStateGroup(Request $request)
+ {
+ try {
+ $createdStateGroup = $this->objectStateService->createObjectStateGroup(
+ $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ )
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */$e->getMessage());
+ }
+
+ return new Values\CreatedObjectStateGroup(
+ [
+ 'objectStateGroup' => $createdStateGroup,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateGroupDeleteController.php b/src/lib/Server/Controller/ObjectState/ObjectStateGroupDeleteController.php
new file mode 100644
index 000000000..379336399
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateGroupDeleteController.php
@@ -0,0 +1,76 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - Object state group deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete an Object state group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The Object state group does not exist.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateGroupDeleteController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * The given object state group including the object states is deleted.
+ *
+ * @param $objectStateGroupId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteObjectStateGroup($objectStateGroupId)
+ {
+ $this->objectStateService->deleteObjectStateGroup(
+ $this->objectStateService->loadObjectStateGroup($objectStateGroupId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateGroupListController.php b/src/lib/Server/Controller/ObjectState/ObjectStateGroupListController.php
new file mode 100644
index 000000000..f0cee501a
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateGroupListController.php
@@ -0,0 +1,94 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list of Object state groups.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectStateGroupList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroupList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/GET/ObjectStateGroupList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read Object state groups.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateGroupListController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Returns a list of all object state groups.
+ *
+ * @return \Ibexa\Rest\Server\Values\ObjectStateGroupList
+ */
+ public function loadObjectStateGroups()
+ {
+ return new Values\ObjectStateGroupList(
+ $this->objectStateService->loadObjectStateGroups(0, -1, Language::ALL)
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateGroupLoadByIdController.php b/src/lib/Server/Controller/ObjectState/ObjectStateGroupLoadByIdController.php
new file mode 100644
index 000000000..5b4abcfec
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateGroupLoadByIdController.php
@@ -0,0 +1,104 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the Object state group.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectStateGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this Object state group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The Object state group does not exist.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateGroupLoadByIdController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Loads an object state group.
+ *
+ * @param $objectStateGroupId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ObjectState\ObjectStateGroup
+ */
+ public function loadObjectStateGroup($objectStateGroupId)
+ {
+ return $this->objectStateService->loadObjectStateGroup($objectStateGroupId, Language::ALL);
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateGroupUpdateController.php b/src/lib/Server/Controller/ObjectState/ObjectStateGroupUpdateController.php
new file mode 100644
index 000000000..bae908913
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateGroupUpdateController.php
@@ -0,0 +1,158 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates an Object state group. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Object State Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Object state group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Object state group input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ObjectStateGroupUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroupUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroupUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Object stated group updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectStateGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/PATCH/ObjectStateGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to update an Object state group.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - An Object state group with the provided identifier already exists.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - The current ETag does not match the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateGroupUpdateController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Updates an object state group.
+ *
+ * @param $objectStateGroupId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\ObjectState\ObjectStateGroup
+ */
+ public function updateObjectStateGroup($objectStateGroupId, Request $request)
+ {
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
+
+ try {
+ $updatedStateGroup = $this->objectStateService->updateObjectStateGroup($objectStateGroup, $updateStruct);
+
+ return $updatedStateGroup;
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateListController.php b/src/lib/Server/Controller/ObjectState/ObjectStateListController.php
new file mode 100644
index 000000000..f40577ce6
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateListController.php
@@ -0,0 +1,107 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list of Object states.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectStateList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/GET/ObjectStateList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read Object states.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateListController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Returns a list of all object states of the given group.
+ *
+ * @param $objectStateGroupId
+ *
+ * @return \Ibexa\Rest\Server\Values\ObjectStateList
+ */
+ public function loadObjectStates($objectStateGroupId)
+ {
+ $objectStateGroup = $this->objectStateService->loadObjectStateGroup($objectStateGroupId);
+
+ return new Values\ObjectStateList(
+ $this->objectStateService->loadObjectStates($objectStateGroup, Language::ALL),
+ $objectStateGroup->id
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateLoadByIdController.php b/src/lib/Server/Controller/ObjectState/ObjectStateLoadByIdController.php
new file mode 100644
index 000000000..d67504c0f
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateLoadByIdController.php
@@ -0,0 +1,117 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the Object state.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectState+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectState',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectState+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this Object state.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The Object state does not exist.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateLoadByIdController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Loads an object state.
+ *
+ * @param $objectStateGroupId
+ * @param $objectStateId
+ *
+ * @return \Ibexa\Rest\Values\RestObjectState
+ */
+ public function loadObjectState($objectStateGroupId, $objectStateId)
+ {
+ return new RestObjectState(
+ $this->objectStateService->loadObjectState($objectStateId, Language::ALL),
+ $objectStateGroupId
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStateUpdateController.php b/src/lib/Server/Controller/ObjectState/ObjectStateUpdateController.php
new file mode 100644
index 000000000..6ea44a773
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStateUpdateController.php
@@ -0,0 +1,168 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates an Object state. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Object State Groups',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Object state is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Object state input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateGroupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'objectStateId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ObjectStateUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectStateUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectStateUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Object State updated',
+ 'content' => [
+ 'application/vnd.ibexa.api.ObjectState+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectState',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ObjectState+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ObjectStateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objectstategroups/object_state_group_id/objectstates/object_state_id/PATCH/ObjectState.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to update the Object state.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - An Object state with the provided identifier already exists in this group.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - The current ETag does not match the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class ObjectStateUpdateController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Updates an object state.
+ *
+ * @param $objectStateGroupId
+ * @param $objectStateId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Values\RestObjectState
+ */
+ public function updateObjectState($objectStateGroupId, $objectStateId, Request $request)
+ {
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $objectState = $this->objectStateService->loadObjectState($objectStateId);
+
+ try {
+ $updatedObjectState = $this->objectStateService->updateObjectState($objectState, $updateStruct);
+
+ return new RestObjectState($updatedObjectState, $objectStateGroupId);
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStatesForContentListController.php b/src/lib/Server/Controller/ObjectState/ObjectStatesForContentListController.php
new file mode 100644
index 000000000..6c06ac362
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStatesForContentListController.php
@@ -0,0 +1,117 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the Object state.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentObjectStates+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStates',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentObjectStates+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStatesWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The content item does not exist.',
+ ],
+ ],
+ ),
+)]
+class ObjectStatesForContentListController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Returns the object states of content.
+ *
+ * @param $contentId
+ *
+ * @return \Ibexa\Rest\Values\ContentObjectStates
+ */
+ public function getObjectStatesForContent($contentId)
+ {
+ $groups = $this->objectStateService->loadObjectStateGroups();
+ $contentInfo = $this->contentService->loadContentInfo($contentId);
+
+ $contentObjectStates = [];
+
+ foreach ($groups as $group) {
+ try {
+ $state = $this->objectStateService->getContentState($contentInfo, $group);
+ $contentObjectStates[] = new RestObjectState($state, $group->id);
+ } catch (NotFoundException $e) {
+ // Do nothing
+ }
+ }
+
+ return new ContentObjectStates($contentObjectStates);
+ }
+}
diff --git a/src/lib/Server/Controller/ObjectState/ObjectStatesForContentUpdateController.php b/src/lib/Server/Controller/ObjectState/ObjectStatesForContentUpdateController.php
new file mode 100644
index 000000000..62cf81136
--- /dev/null
+++ b/src/lib/Server/Controller/ObjectState/ObjectStatesForContentUpdateController.php
@@ -0,0 +1,179 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates Object states of a content item. An Object state in the input overrides the state of the Object state group. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Objects',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Object state is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The content item Object states input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'contentId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ContentObjectStates+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStates',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentObjectStates+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStatesWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'OK - Object state updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.ContentObjectStates+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStates',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/PATCH/ContentObjectStates.response.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ContentObjectStates+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ContentObjectStatesWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/objects/content_id/objectstates/GET/ContentObjectStates.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to set an Object state.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - The input contains multiple Object states of the same Object state group.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - The current ETag does not match the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class ObjectStatesForContentUpdateController extends RestController
+{
+ protected ObjectStateService $objectStateService;
+
+ protected ContentService $contentService;
+
+ public function __construct(ObjectStateService $objectStateService, ContentService $contentService)
+ {
+ $this->objectStateService = $objectStateService;
+ $this->contentService = $contentService;
+ }
+
+ /**
+ * Updates object states of content
+ * An object state in the input overrides the state of the object state group.
+ *
+ * @param $contentId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Values\ContentObjectStates
+ */
+ public function setObjectStatesForContent($contentId, Request $request)
+ {
+ $newObjectStates = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $countByGroups = [];
+ foreach ($newObjectStates as $newObjectState) {
+ $groupId = (int)$newObjectState->groupId;
+ if (array_key_exists($groupId, $countByGroups)) {
+ ++$countByGroups[$groupId];
+ } else {
+ $countByGroups[$groupId] = 1;
+ }
+ }
+
+ foreach ($countByGroups as $groupId => $count) {
+ if ($count > 1) {
+ throw new ForbiddenException(
+ /** @Ignore */
+ "Multiple Object states provided for group with ID $groupId"
+ );
+ }
+ }
+
+ $contentInfo = $this->contentService->loadContentInfo($contentId);
+
+ $contentObjectStates = [];
+ foreach ($newObjectStates as $newObjectState) {
+ $objectStateGroup = $this->objectStateService->loadObjectStateGroup($newObjectState->groupId);
+ $this->objectStateService->setContentState($contentInfo, $objectStateGroup, $newObjectState->objectState);
+ $contentObjectStates[(int)$objectStateGroup->id] = $newObjectState;
+ }
+
+ return new ContentObjectStates($contentObjectStates);
+ }
+}
diff --git a/src/lib/Server/Controller/Role.php b/src/lib/Server/Controller/Role.php
deleted file mode 100644
index 8f9a5d0df..000000000
--- a/src/lib/Server/Controller/Role.php
+++ /dev/null
@@ -1,774 +0,0 @@
-roleService = $roleService;
- $this->userService = $userService;
- $this->locationService = $locationService;
- }
-
- public function createRole(Request $request): Values\CreatedRole
- {
- try {
- $roleDraft = $this->roleService->createRole(
- $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- ],
- $request->getContent()
- )
- )
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (UnauthorizedException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (Exceptions\Parser $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
- }
-
- /**
- * Creates a new RoleDraft for an existing Role.
- *
- * @since 6.2
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ForbiddenException if the Role already has a Role Draft that will need to be removed first,
- * or if the authenticated user is not allowed to create a role
- * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException if a policy limitation in the $roleCreateStruct is not valid
- *
- * @return \Ibexa\Rest\Server\Values\CreatedRole
- */
- public function createRoleDraft($roleId, Request $request)
- {
- try {
- $roleDraft = $this->roleService->createRoleDraft(
- $this->roleService->loadRole($roleId)
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (UnauthorizedException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- } catch (Exceptions\Parser $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
- }
-
- /**
- * Loads list of roles.
- *
- * @return \Ibexa\Rest\Server\Values\RoleList
- */
- public function listRoles(Request $request)
- {
- $roles = [];
- if ($request->query->has('identifier')) {
- try {
- $role = $this->roleService->loadRoleByIdentifier((string)$request->query->get('identifier'));
- $roles[] = $role;
- } catch (APINotFoundException $e) {
- // Do nothing
- }
- } else {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
-
- $roles = array_slice(
- $this->roleService->loadRoles(),
- $offset >= 0 ? $offset : 0,
- $limit >= 0 ? $limit : null
- );
- }
-
- return new Values\RoleList($roles, $request->getPathInfo());
- }
-
- /**
- * Loads role.
- *
- * @param $roleId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\Role
- */
- public function loadRole($roleId)
- {
- return $this->roleService->loadRole($roleId);
- }
-
- /**
- * Loads a role draft.
- *
- * @param mixed $roleId Original role ID, or ID of the role draft itself
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleDraft
- */
- public function loadRoleDraft($roleId)
- {
- try {
- // First try to load the draft for given role.
- return $this->roleService->loadRoleDraftByRoleId($roleId);
- } catch (NotFoundException $e) {
- // We might want a newly created role, so try to load it by its ID.
- // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
- return $this->roleService->loadRoleDraft($roleId);
- }
- }
-
- /**
- * Updates a role.
- *
- * @param $roleId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\Role
- */
- public function updateRole($roleId, Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
- $roleDraft = $this->roleService->createRoleDraft(
- $this->roleService->loadRole($roleId)
- );
- $roleDraft = $this->roleService->updateRoleDraft(
- $roleDraft,
- $this->mapToUpdateStruct($createStruct)
- );
-
- $this->roleService->publishRoleDraft($roleDraft);
-
- return $this->roleService->loadRole($roleId);
- }
-
- /**
- * Updates a role draft.
- *
- * @param mixed $roleId Original role ID, or ID of the role draft itself
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleDraft
- */
- public function updateRoleDraft($roleId, Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- // First try to load the draft for given role.
- $roleDraft = $this->roleService->loadRoleDraftByRoleId($roleId);
- } catch (NotFoundException $e) {
- // We might want a newly created role, so try to load it by its ID.
- // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
- $roleDraft = $this->roleService->loadRoleDraft($roleId);
- }
-
- return $this->roleService->updateRoleDraft($roleDraft, $this->mapToUpdateStruct($createStruct));
- }
-
- /**
- * Publishes a role draft.
- *
- * @param mixed $roleId Original role ID, or ID of the role draft itself
- *
- * @return \Ibexa\Rest\Server\Values\PublishedRole
- */
- public function publishRoleDraft($roleId)
- {
- try {
- // First try to load the draft for given role.
- $roleDraft = $this->roleService->loadRoleDraftByRoleId($roleId);
- } catch (NotFoundException $e) {
- // We might want a newly created role, so try to load it by its ID.
- // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
- $roleDraft = $this->roleService->loadRoleDraft($roleId);
- }
-
- $this->roleService->publishRoleDraft($roleDraft);
-
- $role = $this->roleService->loadRoleByIdentifier($roleDraft->identifier);
-
- return new Values\PublishedRole(['role' => new Values\RestRole($role)]);
- }
-
- /**
- * Delete a role by ID.
- *
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteRole($roleId)
- {
- $this->roleService->deleteRole(
- $this->roleService->loadRole($roleId)
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Delete a role draft by ID.
- *
- * @since 6.2
- *
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteRoleDraft($roleId)
- {
- $this->roleService->deleteRoleDraft(
- $this->roleService->loadRoleDraft($roleId)
- );
-
- return new Values\NoContent();
- }
-
- /**
- * Loads the policies for the role.
- *
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\PolicyList
- */
- public function loadPolicies($roleId, Request $request)
- {
- $loadedRole = $this->roleService->loadRole($roleId);
-
- return new Values\PolicyList($loadedRole->getPolicies(), $request->getPathInfo());
- }
-
- /**
- * Deletes all policies from a role.
- *
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deletePolicies($roleId)
- {
- $loadedRole = $this->roleService->loadRole($roleId);
- $roleDraft = $this->roleService->createRoleDraft($loadedRole);
- /** @var \Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft $policyDraft */
- foreach ($roleDraft->getPolicies() as $policyDraft) {
- $this->roleService->removePolicyByRoleDraft($roleDraft, $policyDraft);
- }
- $this->roleService->publishRoleDraft($roleDraft);
-
- return new Values\NoContent();
- }
-
- /**
- * Loads a policy.
- *
- * @param $roleId
- * @param $policyId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
- */
- public function loadPolicy($roleId, $policyId, Request $request)
- {
- $loadedRole = $this->roleService->loadRole($roleId);
- foreach ($loadedRole->getPolicies() as $policy) {
- if ($policy->id == $policyId) {
- return $policy;
- }
- }
-
- throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Adds a policy to role.
- *
- * @param int $roleId ID of a role draft
- *
- * @return \Ibexa\Rest\Server\Values\CreatedPolicy
- */
- public function addPolicy($roleId, Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- // First try to treat $roleId as a role draft ID.
- $role = $this->roleService->addPolicyByRoleDraft(
- $this->roleService->loadRoleDraft($roleId),
- $createStruct
- );
- } catch (NotFoundException $e) {
- // Then try to treat $roleId as a role ID.
- $roleDraft = $this->roleService->createRoleDraft(
- $this->roleService->loadRole($roleId)
- );
- $roleDraft = $this->roleService->addPolicyByRoleDraft(
- $roleDraft,
- $createStruct
- );
- $this->roleService->publishRoleDraft($roleDraft);
- $role = $this->roleService->loadRole($roleId);
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- return new Values\CreatedPolicy(
- [
- 'policy' => $this->getLastAddedPolicy($role),
- ]
- );
- }
-
- /**
- * Get the last added policy for $role.
- *
- * This is needed because the RoleService addPolicy() and addPolicyByRoleDraft() methods return the role,
- * not the policy.
- *
- * @param $role \Ibexa\Contracts\Core\Repository\Values\User\Role
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
- */
- private function getLastAddedPolicy($role)
- {
- $policies = $role->getPolicies();
-
- $policyToReturn = $policies[0];
- for ($i = 1, $count = count($policies); $i < $count; ++$i) {
- if ($policies[$i]->id > $policyToReturn->id) {
- $policyToReturn = $policies[$i];
- }
- }
-
- return $policyToReturn;
- }
-
- /**
- * Updates a policy.
- *
- * @param int $roleId ID of a role draft
- * @param int $policyId ID of a policy
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
- */
- public function updatePolicy($roleId, $policyId, Request $request)
- {
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
- try {
- // First try to treat $roleId as a role draft ID.
- $roleDraft = $this->roleService->loadRoleDraft($roleId);
- foreach ($roleDraft->getPolicies() as $policy) {
- if ($policy->id == $policyId) {
- try {
- return $this->roleService->updatePolicyByRoleDraft(
- $roleDraft,
- $policy,
- $updateStruct
- );
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- }
- }
- }
- } catch (NotFoundException $e) {
- // Then try to treat $roleId as a role ID.
- $roleDraft = $this->roleService->createRoleDraft(
- $this->roleService->loadRole($roleId)
- );
- foreach ($roleDraft->getPolicies() as $policy) {
- if ($policy->originalId == $policyId) {
- try {
- $policyDraft = $this->roleService->updatePolicyByRoleDraft(
- $roleDraft,
- $policy,
- $updateStruct
- );
- $this->roleService->publishRoleDraft($roleDraft);
- $role = $this->roleService->loadRole($roleId);
-
- foreach ($role->getPolicies() as $newPolicy) {
- if ($newPolicy->id == $policyDraft->id) {
- return $newPolicy;
- }
- }
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- }
- }
- }
- }
-
- throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Delete a policy from role.
- *
- * @param int $roleId ID of a role draft
- * @param int $policyId ID of a policy
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deletePolicy($roleId, $policyId, Request $request)
- {
- try {
- // First try to treat $roleId as a role draft ID.
- $roleDraft = $this->roleService->loadRoleDraft($roleId);
- $policy = null;
- foreach ($roleDraft->getPolicies() as $rolePolicy) {
- if ($rolePolicy->id == $policyId) {
- $policy = $rolePolicy;
- break;
- }
- }
- if ($policy !== null) {
- $this->roleService->removePolicyByRoleDraft($roleDraft, $policy);
-
- return new Values\NoContent();
- }
- } catch (NotFoundException $e) {
- // Then try to treat $roleId as a role ID.
- $roleDraft = $this->roleService->createRoleDraft(
- $this->roleService->loadRole($roleId)
- );
- $policy = null;
- foreach ($roleDraft->getPolicies() as $rolePolicy) {
- if ($rolePolicy->originalId == $policyId) {
- $policy = $rolePolicy;
- break;
- }
- }
- if ($policy !== null) {
- $this->roleService->removePolicyByRoleDraft($roleDraft, $policy);
- $this->roleService->publishRoleDraft($roleDraft);
-
- return new Values\NoContent();
- }
- }
- throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Assigns role to user.
- *
- * @param $userId
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function assignRoleToUser($userId, Request $request)
- {
- $roleAssignment = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $user = $this->userService->loadUser($userId);
- $role = $this->roleService->loadRole($roleAssignment->roleId);
-
- try {
- $this->roleService->assignRoleToUser($role, $user, $roleAssignment->limitation);
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
-
- return new Values\RoleAssignmentList($roleAssignments, $user->id);
- }
-
- /**
- * Assigns role to user group.
- *
- * @param $groupPath
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function assignRoleToUserGroup($groupPath, Request $request)
- {
- $roleAssignment = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- $groupLocationParts = explode('/', $groupPath);
- $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
- $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
-
- $role = $this->roleService->loadRole($roleAssignment->roleId);
-
- try {
- $this->roleService->assignRoleToUserGroup($role, $userGroup, $roleAssignment->limitation);
- } catch (LimitationValidationException $e) {
- throw new BadRequestException($e->getMessage());
- }
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
-
- return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
- }
-
- /**
- * Un-assigns role from user.
- *
- * @param $userId
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function unassignRoleFromUser($userId, $roleId)
- {
- $user = $this->userService->loadUser($userId);
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment->role->id == $roleId) {
- $this->roleService->removeRoleAssignment($roleAssignment);
- }
- }
- $newRoleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
-
- return new Values\RoleAssignmentList($newRoleAssignments, $user->id);
- }
-
- /**
- * Un-assigns role from user group.
- *
- * @param $groupPath
- * @param $roleId
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function unassignRoleFromUserGroup($groupPath, $roleId)
- {
- $groupLocationParts = explode('/', $groupPath);
- $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
- $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment->role->id == $roleId) {
- $this->roleService->removeRoleAssignment($roleAssignment);
- }
- }
- $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
-
- return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
- }
-
- /**
- * Loads role assignments for user.
- *
- * @param $userId
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function loadRoleAssignmentsForUser($userId)
- {
- $user = $this->userService->loadUser($userId);
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
-
- return new Values\RoleAssignmentList($roleAssignments, $user->id);
- }
-
- /**
- * Loads role assignments for user group.
- *
- * @param $groupPath
- *
- * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
- */
- public function loadRoleAssignmentsForUserGroup($groupPath)
- {
- $groupLocationParts = explode('/', $groupPath);
- $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
- $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
-
- return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
- }
-
- /**
- * Returns a role assignment to the given user.
- *
- * @param $userId
- * @param $roleId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\RestUserRoleAssignment
- */
- public function loadRoleAssignmentForUser($userId, $roleId, Request $request)
- {
- $user = $this->userService->loadUser($userId);
- $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
-
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment->getRole()->id == $roleId) {
- return new Values\RestUserRoleAssignment($roleAssignment, $userId);
- }
- }
-
- throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Returns a role assignment to the given user group.
- *
- * @param $groupPath
- * @param $roleId
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- *
- * @return \Ibexa\Rest\Server\Values\RestUserGroupRoleAssignment
- */
- public function loadRoleAssignmentForUserGroup($groupPath, $roleId, Request $request)
- {
- $groupLocationParts = explode('/', $groupPath);
- $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
- $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
-
- $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment->getRole()->id == $roleId) {
- return new Values\RestUserGroupRoleAssignment($roleAssignment, $groupPath);
- }
- }
-
- throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
- }
-
- /**
- * Search all policies which are applied to a given user.
- *
- * @return \Ibexa\Rest\Server\Values\PolicyList
- */
- public function listPoliciesForUser(Request $request)
- {
- $user = $this->userService->loadUser((int)$request->query->get('userId'));
- $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user, true);
-
- $policies = [];
- foreach ($roleAssignments as $roleAssignment) {
- $policies[] = $roleAssignment->getRole()->getPolicies();
- }
-
- return new Values\PolicyList(
- !empty($policies) ? array_merge(...$policies) : [],
- $request->getPathInfo()
- );
- }
-
- /**
- * Maps a RoleCreateStruct to a RoleUpdateStruct.
- *
- * Needed since both structs are encoded into the same media type on input.
- *
- * @param \Ibexa\Contracts\Core\Repository\Values\User\RoleCreateStruct $createStruct
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleUpdateStruct
- */
- protected function mapToUpdateStruct(RoleCreateStruct $createStruct)
- {
- return new RoleUpdateStruct(
- [
- 'identifier' => $createStruct->identifier,
- ]
- );
- }
-}
diff --git a/src/lib/Server/Controller/Role/RoleAssignToUserController.php b/src/lib/Server/Controller/Role/RoleAssignToUserController.php
new file mode 100644
index 000000000..0240f34b7
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignToUserController.php
@@ -0,0 +1,130 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Assigns a Role to a user.',
+ tags: [
+ 'User',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Role assignment list is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleAssignInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RoleAssignInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - validation of limitation in RoleAssignInput fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to assign this Role.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignToUserController extends RoleBaseController
+{
+ /**
+ * Assigns role to user.
+ *
+ * @param $userId
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function assignRoleToUser($userId, Request $request)
+ {
+ $roleAssignment = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $user = $this->userService->loadUser($userId);
+ $role = $this->roleService->loadRole($roleAssignment->roleId);
+
+ try {
+ $this->roleService->assignRoleToUser($role, $user, $roleAssignment->limitation);
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
+
+ return new Values\RoleAssignmentList($roleAssignments, $user->id);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleAssignToUserGroupController.php b/src/lib/Server/Controller/Role/RoleAssignToUserGroupController.php
new file mode 100644
index 000000000..9418ef9cb
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignToUserGroupController.php
@@ -0,0 +1,133 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Assigns a Role to a User Group.',
+ tags: [
+ 'User Group',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Role assignment list is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleAssignInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RoleAssignInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/roles/POST/RoleAssignInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - validation of limitation in RoleAssignInput fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to assign this Role.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignToUserGroupController extends RoleBaseController
+{
+ /**
+ * Assigns role to user group.
+ *
+ * @param $groupPath
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function assignRoleToUserGroup($groupPath, Request $request)
+ {
+ $roleAssignment = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ $groupLocationParts = explode('/', $groupPath);
+ $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
+ $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
+
+ $role = $this->roleService->loadRole($roleAssignment->roleId);
+
+ try {
+ $this->roleService->assignRoleToUserGroup($role, $userGroup, $roleAssignment->limitation);
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
+
+ return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupListController.php b/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupListController.php
new file mode 100644
index 000000000..f223de509
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupListController.php
@@ -0,0 +1,84 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignmentForUserGroupListController extends RoleBaseController
+{
+ /**
+ * Loads role assignments for user group.
+ *
+ * @param $groupPath
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function loadRoleAssignmentsForUserGroup($groupPath)
+ {
+ $groupLocationParts = explode('/', $groupPath);
+ $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
+ $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
+
+ return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupLoadByIdController.php b/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupLoadByIdController.php
new file mode 100644
index 000000000..e7855aea0
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignmentForUserGroupLoadByIdController.php
@@ -0,0 +1,103 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'roleId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a Role assignment of the given User Group.',
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignment+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignment',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignment+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignmentForUserGroupLoadByIdController extends RoleBaseController
+{
+ /**
+ * Returns a role assignment to the given user group.
+ *
+ * @param $groupPath
+ * @param $roleId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestUserGroupRoleAssignment
+ */
+ public function loadRoleAssignmentForUserGroup($groupPath, $roleId, Request $request)
+ {
+ $groupLocationParts = explode('/', $groupPath);
+ $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
+ $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment->getRole()->id == $roleId) {
+ return new Values\RestUserGroupRoleAssignment($roleAssignment, $groupPath);
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleAssignmentForUserListController.php b/src/lib/Server/Controller/Role/RoleAssignmentForUserListController.php
new file mode 100644
index 000000000..a917d69e5
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignmentForUserListController.php
@@ -0,0 +1,82 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignmentForUserListController extends RoleBaseController
+{
+ /**
+ * Loads role assignments for user.
+ *
+ * @param $userId
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function loadRoleAssignmentsForUser($userId)
+ {
+ $user = $this->userService->loadUser($userId);
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
+
+ return new Values\RoleAssignmentList($roleAssignments, $user->id);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleAssignmentForUserLoadByIdController.php b/src/lib/Server/Controller/Role/RoleAssignmentForUserLoadByIdController.php
new file mode 100644
index 000000000..32227c743
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleAssignmentForUserLoadByIdController.php
@@ -0,0 +1,101 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'roleId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Role assignment to the given User Group.',
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignment+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignment',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignment+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RoleAssignmentForUserLoadByIdController extends RoleBaseController
+{
+ /**
+ * Returns a role assignment to the given user.
+ *
+ * @param $userId
+ * @param $roleId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\RestUserRoleAssignment
+ */
+ public function loadRoleAssignmentForUser($userId, $roleId, Request $request)
+ {
+ $user = $this->userService->loadUser($userId);
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
+
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment->getRole()->id == $roleId) {
+ return new Values\RestUserRoleAssignment($roleAssignment, $userId);
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleBaseController.php b/src/lib/Server/Controller/Role/RoleBaseController.php
new file mode 100644
index 000000000..5ff9369ff
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleBaseController.php
@@ -0,0 +1,77 @@
+roleService = $roleService;
+ $this->userService = $userService;
+ $this->locationService = $locationService;
+ }
+
+ /**
+ * Get the last added policy for $role.
+ *
+ * This is needed because the RoleService addPolicy() and addPolicyByRoleDraft() methods return the role,
+ * not the policy.
+ *
+ * @param $role \Ibexa\Contracts\Core\Repository\Values\User\Role
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
+ */
+ protected function getLastAddedPolicy($role)
+ {
+ $policies = $role->getPolicies();
+
+ $policyToReturn = $policies[0];
+ for ($i = 1, $count = count($policies); $i < $count; ++$i) {
+ if ($policies[$i]->id > $policyToReturn->id) {
+ $policyToReturn = $policies[$i];
+ }
+ }
+
+ return $policyToReturn;
+ }
+
+ /**
+ * Maps a RoleCreateStruct to a RoleUpdateStruct.
+ *
+ * Needed since both structs are encoded into the same media type on input.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\Values\User\RoleCreateStruct $createStruct
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleUpdateStruct
+ */
+ protected function mapToUpdateStruct(RoleCreateStruct $createStruct)
+ {
+ return new RoleUpdateStruct(
+ [
+ 'identifier' => $createStruct->identifier,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleCreateController.php b/src/lib/Server/Controller/Role/RoleCreateController.php
new file mode 100644
index 000000000..91b20c340
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleCreateController.php
@@ -0,0 +1,152 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Role or Role draft.',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new user is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleInput schema encoded in XML or JSON.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RoleInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Role+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Role',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Role+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create a Role or a Role draft.',
+ ],
+ ],
+ ),
+)]
+class RoleCreateController extends RoleBaseController
+{
+ /**
+ * Create new role.
+ *
+ * Defaults to publishing the role, but you can create a draft instead by setting the POST parameter publish=false
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedRole
+ */
+ public function createRole(Request $request)
+ {
+ $publish = (
+ !$request->query->has('publish') ||
+ ($request->query->has('publish') && $request->query->get('publish') === 'true')
+ );
+
+ try {
+ $roleDraft = $this->roleService->createRole(
+ $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ // @todo Needs refactoring! Temporary solution so parser has access to get parameters
+ '__publish' => $publish,
+ ],
+ $request->getContent()
+ )
+ )
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (UnauthorizedException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (Exceptions\Parser $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ if ($publish) {
+ @trigger_error(
+ "Create and publish role in the same operation is deprecated, and will be removed in the future.\n" .
+ 'Instead, publish the role draft using Role::publishRoleDraft().',
+ E_USER_DEPRECATED
+ );
+
+ $this->roleService->publishRoleDraft($roleDraft);
+
+ $role = $this->roleService->loadRole($roleDraft->id);
+
+ return new Values\CreatedRole(['role' => new Values\RestRole($role)]);
+ }
+
+ return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDeleteController.php b/src/lib/Server/Controller/Role/RoleDeleteController.php
new file mode 100644
index 000000000..1ec18962c
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDeleteController.php
@@ -0,0 +1,60 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the User is not authorized to delete this Role.',
+ ],
+ ],
+ ),
+)]
+class RoleDeleteController extends RoleBaseController
+{
+ /**
+ * Delete a role by ID.
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteRole($roleId)
+ {
+ $this->roleService->deleteRole(
+ $this->roleService->loadRole($roleId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDraftCreateController.php b/src/lib/Server/Controller/Role/RoleDraftCreateController.php
new file mode 100644
index 000000000..4ee12a3e0
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDraftCreateController.php
@@ -0,0 +1,118 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Role draft from an existing Role.',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new user is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleInput schema encoded in XML or JSON.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleDraft+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleDraft',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/POST/RoleDraft.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleDraft+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleDraftWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create a Role or a Role draft',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+class RoleDraftCreateController extends RoleBaseController
+{
+ /**
+ * Creates a new RoleDraft for an existing Role.
+ *
+ * @since 6.2
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ForbiddenException if the Role already has a Role Draft that will need to be removed first,
+ * or if the authenticated user is not allowed to create a role
+ * @throws \Ibexa\Rest\Server\Exceptions\BadRequestException if a policy limitation in the $roleCreateStruct is not valid
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedRole
+ */
+ public function createRoleDraft($roleId, Request $request)
+ {
+ try {
+ $roleDraft = $this->roleService->createRoleDraft(
+ $this->roleService->loadRole($roleId)
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (UnauthorizedException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ } catch (Exceptions\Parser $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDraftDeleteController.php b/src/lib/Server/Controller/Role/RoleDraftDeleteController.php
new file mode 100644
index 000000000..44c2f6b20
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDraftDeleteController.php
@@ -0,0 +1,62 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this Role.',
+ ],
+ ],
+ ),
+)]
+class RoleDraftDeleteController extends RoleBaseController
+{
+ /**
+ * Delete a role draft by ID.
+ *
+ * @since 6.2
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteRoleDraft($roleId)
+ {
+ $this->roleService->deleteRoleDraft(
+ $this->roleService->loadRoleDraft($roleId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDraftLoadByRoleIdController.php b/src/lib/Server/Controller/Role/RoleDraftLoadByRoleIdController.php
new file mode 100644
index 000000000..b27b577f8
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDraftLoadByRoleIdController.php
@@ -0,0 +1,98 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Role draft by original Role ID.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Role+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Role',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Role+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - there is no draft or Role with the given ID.',
+ ],
+ ],
+ ),
+)]
+class RoleDraftLoadByRoleIdController extends RoleBaseController
+{
+ /**
+ * Loads a role draft.
+ *
+ * @param mixed $roleId Original role ID, or ID of the role draft itself
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleDraft
+ */
+ public function loadRoleDraft($roleId)
+ {
+ try {
+ // First try to load the draft for given role.
+ return $this->roleService->loadRoleDraftByRoleId($roleId);
+ } catch (NotFoundException $e) {
+ // We might want a newly created role, so try to load it by its ID.
+ // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
+ return $this->roleService->loadRoleDraft($roleId);
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDraftPublishController.php b/src/lib/Server/Controller/Role/RoleDraftPublishController.php
new file mode 100644
index 000000000..454e533f8
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDraftPublishController.php
@@ -0,0 +1,39 @@
+roleService->loadRoleDraftByRoleId($roleId);
+ } catch (NotFoundException $e) {
+ // We might want a newly created role, so try to load it by its ID.
+ // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
+ $roleDraft = $this->roleService->loadRoleDraft($roleId);
+ }
+
+ $this->roleService->publishRoleDraft($roleDraft);
+
+ $role = $this->roleService->loadRoleByIdentifier($roleDraft->identifier);
+
+ return new Values\PublishedRole(['role' => new Values\RestRole($role)]);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleDraftUpdateController.php b/src/lib/Server/Controller/Role/RoleDraftUpdateController.php
new file mode 100644
index 000000000..db02f7f87
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleDraftUpdateController.php
@@ -0,0 +1,142 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a Role draft. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Role is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'Performs a PATCH only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RoleInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Role draft updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Role+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Role',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Role+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update the Role.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - there is no draft or Role with the given ID.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class RoleDraftUpdateController extends RoleBaseController
+{
+ /**
+ * Updates a role draft.
+ *
+ * @param mixed $roleId Original role ID, or ID of the role draft itself
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\RoleDraft
+ */
+ public function updateRoleDraft($roleId, Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ // First try to load the draft for given role.
+ $roleDraft = $this->roleService->loadRoleDraftByRoleId($roleId);
+ } catch (NotFoundException $e) {
+ // We might want a newly created role, so try to load it by its ID.
+ // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
+ $roleDraft = $this->roleService->loadRoleDraft($roleId);
+ }
+
+ return $this->roleService->updateRoleDraft($roleDraft, $this->mapToUpdateStruct($createStruct));
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleListController.php b/src/lib/Server/Controller/Role/RoleListController.php
new file mode 100644
index 000000000..30ba8baae
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleListController.php
@@ -0,0 +1,90 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - list of all Roles.',
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/GET/RoleList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/GET/RoleList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RoleListController extends RoleBaseController
+{
+ /**
+ * Loads list of roles.
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleList
+ */
+ public function listRoles(Request $request)
+ {
+ $roles = [];
+ if ($request->query->has('identifier')) {
+ try {
+ $role = $this->roleService->loadRoleByIdentifier($request->query->get('identifier'));
+ $roles[] = $role;
+ } catch (APINotFoundException $e) {
+ // Do nothing
+ }
+ } else {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
+
+ $roles = array_slice(
+ $this->roleService->loadRoles(),
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : null
+ );
+ }
+
+ return new Values\RoleList($roles, $request->getPathInfo());
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleLoadByIdController.php b/src/lib/Server/Controller/Role/RoleLoadByIdController.php
new file mode 100644
index 000000000..649226840
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleLoadByIdController.php
@@ -0,0 +1,90 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Role for the given ID.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Role+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Role',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Role+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role does not exist.',
+ ],
+ ],
+ ),
+)]
+class RoleLoadByIdController extends RoleBaseController
+{
+ /**
+ * Loads role.
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\Role
+ */
+ public function loadRole($roleId)
+ {
+ return $this->roleService->loadRole($roleId);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePoliciesForUserListController.php b/src/lib/Server/Controller/Role/RolePoliciesForUserListController.php
new file mode 100644
index 000000000..41e72e23f
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePoliciesForUserListController.php
@@ -0,0 +1,81 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Policies which are applied to a given User.',
+ 'content' => [
+ 'application/vnd.ibexa.api.PolicyList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.PolicyList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ ],
+ ),
+)]
+class RolePoliciesForUserListController extends RoleBaseController
+{
+ /**
+ * Search all policies which are applied to a given user.
+ *
+ * @return \Ibexa\Rest\Server\Values\PolicyList
+ */
+ public function listPoliciesForUser(Request $request)
+ {
+ $user = $this->userService->loadUser((int)$request->query->get('userId'));
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user, true);
+
+ $policies = [];
+ foreach ($roleAssignments as $roleAssignment) {
+ $policies[] = $roleAssignment->getRole()->getPolicies();
+ }
+
+ return new Values\PolicyList(
+ !empty($policies) ? array_merge(...$policies) : [],
+ $request->getPathInfo()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyCreateController.php b/src/lib/Server/Controller/Role/RolePolicyCreateController.php
new file mode 100644
index 000000000..99c36205e
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyCreateController.php
@@ -0,0 +1,147 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a Policy',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Policy is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Policy is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.PolicyCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/POST/PolicyCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.PolicyCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyCreateWrapper',
+ ],
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Policy+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Policy',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Policy+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition or validation of limitation in PolicyCreate fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create the Policy.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role does not exist.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyCreateController extends RoleBaseController
+{
+ /**
+ * Adds a policy to role.
+ *
+ * @param int $roleId ID of a role draft
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedPolicy
+ */
+ public function addPolicy($roleId, Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ // First try to treat $roleId as a role draft ID.
+ $role = $this->roleService->addPolicyByRoleDraft(
+ $this->roleService->loadRoleDraft($roleId),
+ $createStruct
+ );
+ } catch (NotFoundException $e) {
+ // Then try to treat $roleId as a role ID.
+ $roleDraft = $this->roleService->createRoleDraft(
+ $this->roleService->loadRole($roleId)
+ );
+ $roleDraft = $this->roleService->addPolicyByRoleDraft(
+ $roleDraft,
+ $createStruct
+ );
+ $this->roleService->publishRoleDraft($roleDraft);
+ $role = $this->roleService->loadRole($roleId);
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+
+ return new Values\CreatedPolicy(
+ [
+ 'policy' => $this->getLastAddedPolicy($role),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyDeleteAllFromRoleController.php b/src/lib/Server/Controller/Role/RolePolicyDeleteAllFromRoleController.php
new file mode 100644
index 000000000..f2b59e486
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyDeleteAllFromRoleController.php
@@ -0,0 +1,64 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - all Policies of the given Role are deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this content type.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyDeleteAllFromRoleController extends RoleBaseController
+{
+ /**
+ * Deletes all policies from a role.
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deletePolicies($roleId)
+ {
+ $loadedRole = $this->roleService->loadRole($roleId);
+ $roleDraft = $this->roleService->createRoleDraft($loadedRole);
+ /** @var \Ibexa\Contracts\Core\Repository\Values\User\PolicyDraft $policyDraft */
+ foreach ($roleDraft->getPolicies() as $policyDraft) {
+ $this->roleService->removePolicyByRoleDraft($roleDraft, $policyDraft);
+ }
+ $this->roleService->publishRoleDraft($roleDraft);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyDeleteController.php b/src/lib/Server/Controller/Role/RolePolicyDeleteController.php
new file mode 100644
index 000000000..469b6b140
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyDeleteController.php
@@ -0,0 +1,99 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - the given Policy is deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this content type.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role or Policy does not exist.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyDeleteController extends RoleBaseController
+{
+ /**
+ * Delete a policy from role.
+ *
+ * @param int $roleId ID of a role draft
+ * @param int $policyId ID of a policy
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deletePolicy($roleId, $policyId, Request $request)
+ {
+ try {
+ // First try to treat $roleId as a role draft ID.
+ $roleDraft = $this->roleService->loadRoleDraft($roleId);
+ $policy = null;
+ foreach ($roleDraft->getPolicies() as $rolePolicy) {
+ if ($rolePolicy->id == $policyId) {
+ $policy = $rolePolicy;
+ break;
+ }
+ }
+ if ($policy !== null) {
+ $this->roleService->removePolicyByRoleDraft($roleDraft, $policy);
+
+ return new Values\NoContent();
+ }
+ } catch (NotFoundException $e) {
+ // Then try to treat $roleId as a role ID.
+ $roleDraft = $this->roleService->createRoleDraft(
+ $this->roleService->loadRole($roleId)
+ );
+ $policy = null;
+ foreach ($roleDraft->getPolicies() as $rolePolicy) {
+ if ($rolePolicy->originalId == $policyId) {
+ $policy = $rolePolicy;
+ break;
+ }
+ }
+ if ($policy !== null) {
+ $this->roleService->removePolicyByRoleDraft($roleDraft, $policy);
+ $this->roleService->publishRoleDraft($roleDraft);
+
+ return new Values\NoContent();
+ }
+ }
+ throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyListController.php b/src/lib/Server/Controller/Role/RolePolicyListController.php
new file mode 100644
index 000000000..5f6a10802
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyListController.php
@@ -0,0 +1,84 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.PolicyList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.PolicyList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/GET/PolicyList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role does not exist.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyListController extends RoleBaseController
+{
+ /**
+ * Loads the policies for the role.
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\PolicyList
+ */
+ public function loadPolicies($roleId, Request $request)
+ {
+ $loadedRole = $this->roleService->loadRole($roleId);
+
+ return new Values\PolicyList($loadedRole->getPolicies(), $request->getPathInfo());
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyLoadByIdController.php b/src/lib/Server/Controller/Role/RolePolicyLoadByIdController.php
new file mode 100644
index 000000000..b488bbc74
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyLoadByIdController.php
@@ -0,0 +1,101 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'policyId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Policy+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Policy',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Policy+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Roles.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role or Policy does not exist.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyLoadByIdController extends RoleBaseController
+{
+ /**
+ * Loads a policy.
+ *
+ * @param $roleId
+ * @param $policyId
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
+ */
+ public function loadPolicy($roleId, $policyId, Request $request)
+ {
+ $loadedRole = $this->roleService->loadRole($roleId);
+ foreach ($loadedRole->getPolicies() as $policy) {
+ if ($policy->id == $policyId) {
+ return $policy;
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RolePolicyUpdateController.php b/src/lib/Server/Controller/Role/RolePolicyUpdateController.php
new file mode 100644
index 000000000..a84fe1e5b
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RolePolicyUpdateController.php
@@ -0,0 +1,180 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a Policy. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Policy is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Policy is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'Causes to patch only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'policyId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.PolicyUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/PolicyUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.PolicyUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyUpdateWrapper',
+ ],
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Policy+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Policy',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/PATCH/Policy.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Policy+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/PolicyWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/policies/id/GET/Policy.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition or validation of limitation in PolicyUpdate fails.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update the Policy.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Role does not exist.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class RolePolicyUpdateController extends RoleBaseController
+{
+ /**
+ * Updates a policy.
+ *
+ * @param int $roleId ID of a role draft
+ * @param int $policyId ID of a policy
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\Policy
+ */
+ public function updatePolicy($roleId, $policyId, Request $request)
+ {
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+ try {
+ // First try to treat $roleId as a role draft ID.
+ $roleDraft = $this->roleService->loadRoleDraft($roleId);
+ foreach ($roleDraft->getPolicies() as $policy) {
+ if ($policy->id == $policyId) {
+ try {
+ return $this->roleService->updatePolicyByRoleDraft(
+ $roleDraft,
+ $policy,
+ $updateStruct
+ );
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+ }
+ }
+ } catch (NotFoundException $e) {
+ // Then try to treat $roleId as a role ID.
+ $roleDraft = $this->roleService->createRoleDraft(
+ $this->roleService->loadRole($roleId)
+ );
+ foreach ($roleDraft->getPolicies() as $policy) {
+ if ($policy->originalId == $policyId) {
+ try {
+ $policyDraft = $this->roleService->updatePolicyByRoleDraft(
+ $roleDraft,
+ $policy,
+ $updateStruct
+ );
+ $this->roleService->publishRoleDraft($roleDraft);
+ $role = $this->roleService->loadRole($roleId);
+
+ foreach ($role->getPolicies() as $newPolicy) {
+ if ($newPolicy->id == $policyDraft->id) {
+ return $newPolicy;
+ }
+ }
+ } catch (LimitationValidationException $e) {
+ throw new BadRequestException($e->getMessage());
+ }
+ }
+ }
+ }
+
+ throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleUnassignFromUserController.php b/src/lib/Server/Controller/Role/RoleUnassignFromUserController.php
new file mode 100644
index 000000000..8db3d6a60
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleUnassignFromUserController.php
@@ -0,0 +1,97 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'roleId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/POST/RoleAssignmentList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this content type.',
+ ],
+ ],
+ ),
+)]
+class RoleUnassignFromUserController extends RoleBaseController
+{
+ /**
+ * Un-assigns role from user.
+ *
+ * @param $userId
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function unassignRoleFromUser($userId, $roleId)
+ {
+ $user = $this->userService->loadUser($userId);
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment->role->id == $roleId) {
+ $this->roleService->removeRoleAssignment($roleAssignment);
+ }
+ }
+ $newRoleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
+
+ return new Values\RoleAssignmentList($newRoleAssignments, $user->id);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleUnassignFromUserGroupController.php b/src/lib/Server/Controller/Role/RoleUnassignFromUserGroupController.php
new file mode 100644
index 000000000..037e6c9ba
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleUnassignFromUserGroupController.php
@@ -0,0 +1,99 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'roleId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.RoleAssignmentList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/GET/RoleAssignment.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleAssignmentList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleAssignmentListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/roles/role_id/DELETE/RoleAssignmentList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this Role assignment.',
+ ],
+ ],
+ ),
+)]
+class RoleUnassignFromUserGroupController extends RoleBaseController
+{
+ /**
+ * Un-assigns role from user group.
+ *
+ * @param $groupPath
+ * @param $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\RoleAssignmentList
+ */
+ public function unassignRoleFromUserGroup($groupPath, $roleId)
+ {
+ $groupLocationParts = explode('/', $groupPath);
+ $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
+ $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
+
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment->role->id == $roleId) {
+ $this->roleService->removeRoleAssignment($roleAssignment);
+ }
+ }
+ $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
+
+ return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
+ }
+}
diff --git a/src/lib/Server/Controller/Role/RoleUpdateController.php b/src/lib/Server/Controller/Role/RoleUpdateController.php
new file mode 100644
index 000000000..b2e55012c
--- /dev/null
+++ b/src/lib/Server/Controller/Role/RoleUpdateController.php
@@ -0,0 +1,138 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a Role. PATCH or POST with header X-HTTP-Method-Override PATCH',
+ tags: [
+ 'User Role',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new user is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The RoleInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag Causes to patch only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'id',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.RoleInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.RoleInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/POST/RoleInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Role updated',
+ 'content' => [
+ 'application/vnd.ibexa.api.Role+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Role',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Role+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RoleWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/roles/id/draft/PATCH/Role.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update the Role.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the provided one in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class RoleUpdateController extends RoleBaseController
+{
+ /**
+ * Updates a role.
+ *
+ * @param $roleId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\User\Role
+ */
+ public function updateRole($roleId, Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+ $roleDraft = $this->roleService->createRoleDraft(
+ $this->roleService->loadRole($roleId)
+ );
+ $roleDraft = $this->roleService->updateRoleDraft(
+ $roleDraft,
+ $this->mapToUpdateStruct($createStruct)
+ );
+
+ $this->roleService->publishRoleDraft($roleDraft);
+
+ return $this->roleService->loadRole($roleId);
+ }
+}
diff --git a/src/lib/Server/Controller/Root.php b/src/lib/Server/Controller/Root.php
index f1743ff96..d643a4950 100644
--- a/src/lib/Server/Controller/Root.php
+++ b/src/lib/Server/Controller/Root.php
@@ -7,9 +7,51 @@
namespace Ibexa\Rest\Server\Controller;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\OpenApi\Model;
use Ibexa\Contracts\Rest\Exceptions\NotFoundException;
use Ibexa\Rest\Server\Controller as RestController;
+use Symfony\Component\HttpFoundation\Response;
+#[Get(
+ uriTemplate: '/',
+ name: 'List of root resources',
+ openapi: new Model\Operation(
+ summary: 'Lists the root resources of the Ibexa Platform installation.',
+ tags: [
+ 'Root',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the list is return in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Root+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Root',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/GET/Root.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Root+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/RootWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/GET/Root.json.example',
+ ],
+ ],
+ ],
+ ],
+ ),
+)]
/**
* Root controller.
*/
diff --git a/src/lib/Server/Controller/Section.php b/src/lib/Server/Controller/Section.php
deleted file mode 100644
index 0f3454dc2..000000000
--- a/src/lib/Server/Controller/Section.php
+++ /dev/null
@@ -1,177 +0,0 @@
-sectionService = $sectionService;
- }
-
- /**
- * List sections.
- *
- * @return \Ibexa\Rest\Server\Values\SectionList
- */
- public function listSections(Request $request)
- {
- if ($request->query->has('identifier')) {
- $sections = [
- $this->loadSectionByIdentifier($request),
- ];
- } else {
- $sections = $this->sectionService->loadSections();
- }
-
- return new Values\SectionList($sections, $request->getPathInfo());
- }
-
- /**
- * Loads section by identifier.
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
- */
- public function loadSectionByIdentifier(Request $request)
- {
- return $this->sectionService->loadSectionByIdentifier(
- // GET variable
- $request->query->get('identifier')
- );
- }
-
- /**
- * Create new section.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedSection
- */
- public function createSection(Request $request)
- {
- try {
- $createdSection = $this->sectionService->createSection(
- $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- )
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\CreatedSection(
- [
- 'section' => $createdSection,
- ]
- );
- }
-
- /**
- * Loads a section.
- *
- * @param $sectionId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
- */
- public function loadSection($sectionId)
- {
- return $this->sectionService->loadSection($sectionId);
- }
-
- /**
- * Updates a section.
- *
- * @param $sectionId
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
- */
- public function updateSection($sectionId, Request $request)
- {
- $createStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- return $this->sectionService->updateSection(
- $this->sectionService->loadSection($sectionId),
- $this->mapToUpdateStruct($createStruct)
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- /**
- * Delete a section by ID.
- *
- * @param $sectionId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteSection($sectionId)
- {
- $this->sectionService->deleteSection(
- $this->sectionService->loadSection($sectionId)
- );
-
- return new NoContent();
- }
-
- /**
- * Maps a SectionCreateStruct to a SectionUpdateStruct.
- *
- * Needed since both structs are encoded into the same media type on input.
- *
- * @param \Ibexa\Contracts\Core\Repository\Values\Content\SectionCreateStruct $createStruct
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\SectionUpdateStruct
- */
- protected function mapToUpdateStruct(SectionCreateStruct $createStruct)
- {
- return new SectionUpdateStruct(
- [
- 'name' => $createStruct->name,
- 'identifier' => $createStruct->identifier,
- ]
- );
- }
-}
diff --git a/src/lib/Server/Controller/Section/SectionCreateController.php b/src/lib/Server/Controller/Section/SectionCreateController.php
new file mode 100644
index 000000000..1f2aa66fa
--- /dev/null
+++ b/src/lib/Server/Controller/Section/SectionCreateController.php
@@ -0,0 +1,124 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new Section.',
+ tags: [
+ 'Section',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new Section is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Section input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.SectionInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/POST/SectionInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.SectionInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/POST/SectionInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Section+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Section',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Section+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example',
+ ],
+ ],
+ ],
+ ],
+ ),
+)]
+class SectionCreateController extends RestController
+{
+ protected SectionService $sectionService;
+
+ public function __construct(SectionService $sectionService)
+ {
+ $this->sectionService = $sectionService;
+ }
+
+ /**
+ * Create new section.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedSection
+ */
+ public function createSection(Request $request)
+ {
+ try {
+ $createdSection = $this->sectionService->createSection(
+ $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ )
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\CreatedSection(
+ [
+ 'section' => $createdSection,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Section/SectionDeleteController.php b/src/lib/Server/Controller/Section/SectionDeleteController.php
new file mode 100644
index 000000000..8336ea130
--- /dev/null
+++ b/src/lib/Server/Controller/Section/SectionDeleteController.php
@@ -0,0 +1,72 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - given Section is deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this Section.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Section does not exist.',
+ ],
+ ],
+ ),
+)]
+class SectionDeleteController extends RestController
+{
+ protected SectionService $sectionService;
+
+ public function __construct(SectionService $sectionService)
+ {
+ $this->sectionService = $sectionService;
+ }
+
+ /**
+ * Delete a section by ID.
+ *
+ * @param $sectionId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteSection($sectionId)
+ {
+ $this->sectionService->deleteSection(
+ $this->sectionService->loadSection($sectionId)
+ );
+
+ return new NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Section/SectionListController.php b/src/lib/Server/Controller/Section/SectionListController.php
new file mode 100644
index 000000000..d1493c8bd
--- /dev/null
+++ b/src/lib/Server/Controller/Section/SectionListController.php
@@ -0,0 +1,108 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.SectionList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/GET/SectionList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.SectionList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/GET/SectionList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read the Section.',
+ ],
+ ],
+ ),
+)]
+class SectionListController extends RestController
+{
+ protected SectionService $sectionService;
+
+ public function __construct(SectionService $sectionService)
+ {
+ $this->sectionService = $sectionService;
+ }
+
+ /**
+ * List sections.
+ *
+ * @return \Ibexa\Rest\Server\Values\SectionList
+ */
+ public function listSections(Request $request)
+ {
+ if ($request->query->has('identifier')) {
+ $sections = [
+ $this->loadSectionByIdentifier($request),
+ ];
+ } else {
+ $sections = $this->sectionService->loadSections();
+ }
+
+ return new Values\SectionList($sections, $request->getPathInfo());
+ }
+
+ /**
+ * Loads section by identifier.
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
+ */
+ public function loadSectionByIdentifier(Request $request)
+ {
+ return $this->sectionService->loadSectionByIdentifier(
+ // GET variable
+ $request->query->get('identifier')
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Section/SectionLoadByIdController.php b/src/lib/Server/Controller/Section/SectionLoadByIdController.php
new file mode 100644
index 000000000..046dda218
--- /dev/null
+++ b/src/lib/Server/Controller/Section/SectionLoadByIdController.php
@@ -0,0 +1,98 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'sectionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Section+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Section',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Section+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read this Section.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The Section does not exist.',
+ ],
+ ],
+ ),
+)]
+class SectionLoadByIdController extends RestController
+{
+ protected SectionService $sectionService;
+
+ public function __construct(SectionService $sectionService)
+ {
+ $this->sectionService = $sectionService;
+ }
+
+ /**
+ * Loads a section.
+ *
+ * @param $sectionId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
+ */
+ public function loadSection($sectionId)
+ {
+ return $this->sectionService->loadSection($sectionId);
+ }
+}
diff --git a/src/lib/Server/Controller/Section/SectionUpdateController.php b/src/lib/Server/Controller/Section/SectionUpdateController.php
new file mode 100644
index 000000000..ac9a43258
--- /dev/null
+++ b/src/lib/Server/Controller/Section/SectionUpdateController.php
@@ -0,0 +1,173 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a Section. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'Section',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated Section is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The Section input schema encoded in XML or JSON.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'sectionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.SectionInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/POST/SectionInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.SectionInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/POST/SectionInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Section updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Section+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Section',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Section+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SectionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/sections/section_id/PATCH/Section.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this Section.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - a Section with the given identifier already exists.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+class SectionUpdateController extends RestController
+{
+ protected SectionService $sectionService;
+
+ public function __construct(SectionService $sectionService)
+ {
+ $this->sectionService = $sectionService;
+ }
+
+ /**
+ * Updates a section.
+ *
+ * @param $sectionId
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\Section
+ */
+ public function updateSection($sectionId, Request $request)
+ {
+ $createStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ return $this->sectionService->updateSection(
+ $this->sectionService->loadSection($sectionId),
+ $this->mapToUpdateStruct($createStruct)
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+
+ /**
+ * Maps a SectionCreateStruct to a SectionUpdateStruct.
+ *
+ * Needed since both structs are encoded into the same media type on input.
+ *
+ * @param \Ibexa\Contracts\Core\Repository\Values\Content\SectionCreateStruct $createStruct
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\SectionUpdateStruct
+ */
+ protected function mapToUpdateStruct(SectionCreateStruct $createStruct)
+ {
+ return new SectionUpdateStruct(
+ [
+ 'name' => $createStruct->name,
+ 'identifier' => $createStruct->identifier,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Services.php b/src/lib/Server/Controller/Services.php
index 53969dea9..ab487806c 100644
--- a/src/lib/Server/Controller/Services.php
+++ b/src/lib/Server/Controller/Services.php
@@ -7,9 +7,50 @@
namespace Ibexa\Rest\Server\Controller;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\OpenApi\Model;
use Ibexa\Rest\Server\Controller as RestController;
use Ibexa\Rest\Server\Values;
+use Symfony\Component\HttpFoundation\Response;
+#[Get(
+ uriTemplate: '/services/countries',
+ name: 'Countries list',
+ openapi: new Model\Operation(
+ summary: 'Gives access to an ISO-3166 formatted list of world countries. It is useful when presenting a country options list from any application.',
+ tags: [
+ 'Services',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the country list is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.CountriesList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/CountryList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/services/countries/GET/CountriesList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.CountriesList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/CountryListWrapper',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ),
+)]
/**
* Services controller.
*/
diff --git a/src/lib/Server/Controller/Session/SessionBaseController.php b/src/lib/Server/Controller/Session/SessionBaseController.php
new file mode 100644
index 000000000..36d0e11a7
--- /dev/null
+++ b/src/lib/Server/Controller/Session/SessionBaseController.php
@@ -0,0 +1,98 @@
+csrfTokenManager->hasToken($this->csrfTokenIntention);
+ }
+
+ /**
+ * Checks the presence / validity of the CSRF token.
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException if the token is missing or invalid
+ */
+ protected function checkCsrfToken(Request $request): void
+ {
+ if (!$request->headers->has('X-CSRF-Token')) {
+ throw $this->createInvalidCsrfTokenException($request);
+ }
+
+ $csrfToken = new CsrfToken(
+ $this->csrfTokenIntention,
+ $request->headers->get('X-CSRF-Token')
+ );
+
+ if (!$this->csrfTokenManager->isTokenValid($csrfToken)) {
+ throw $this->createInvalidCsrfTokenException($request);
+ }
+ }
+
+ protected function getCsrfToken(): string
+ {
+ return $this->csrfTokenManager->getToken($this->csrfTokenIntention)->getValue();
+ }
+
+ protected function createInvalidCsrfTokenException(Request $request): UnauthorizedException
+ {
+ return new UnauthorizedException('Missing or invalid CSRF token');
+ }
+
+ protected function logout(Request $request): Response
+ {
+ $path = '/';
+ $domain = null;
+
+ $session = $this->configResolver->getParameter('session');
+ if (array_key_exists('cookie_domain', $session)) {
+ $domain = $session['cookie_domain'];
+ }
+
+ if (array_key_exists('cookie_path', $session)) {
+ $path = $session['cookie_path'];
+ }
+
+ $response = new Response();
+ $requestSession = $request->getSession();
+
+ $response->headers->clearCookie(
+ $requestSession->getName(),
+ $path,
+ $domain
+ );
+
+ $response->setStatusCode(Response::HTTP_NOT_FOUND);
+ $requestSession->clear();
+
+ return $response;
+ }
+}
diff --git a/src/lib/Server/Controller/Session/SessionCheckController.php b/src/lib/Server/Controller/Session/SessionCheckController.php
new file mode 100644
index 000000000..d81098ee8
--- /dev/null
+++ b/src/lib/Server/Controller/Session/SessionCheckController.php
@@ -0,0 +1,96 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the session is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'User is currently logged in and has a valid session.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Session+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Session',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Session+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'User does not have a valid session, or it has expired.',
+ ],
+ ],
+ ),
+)]
+/**
+ * @internal
+ */
+final class SessionCheckController extends SessionBaseController
+{
+ /**
+ * @return \Ibexa\Rest\Server\Values\UserSession|\Symfony\Component\HttpFoundation\Response
+ */
+ public function checkSessionAction(Request $request)
+ {
+ $session = $request->getSession();
+ if ($session === null || !$session->isStarted()) {
+ return $this->logout($request);
+ }
+
+ $currentUser = $this->userService->loadUser(
+ $this->permissionResolver->getCurrentUserReference()->getUserId()
+ );
+
+ return new Values\UserSession(
+ $currentUser,
+ $session->getName(),
+ $session->getId(),
+ $this->getCsrfToken(),
+ false
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Session/SessionCreateController.php b/src/lib/Server/Controller/Session/SessionCreateController.php
new file mode 100644
index 000000000..2742cfb41
--- /dev/null
+++ b/src/lib/Server/Controller/Session/SessionCreateController.php
@@ -0,0 +1,171 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Performs a login for the user or checks if session exists and returns the session and session cookie. The client will need to remember both session name/ID and CSRF token as this is for security reasons not exposed via GET.',
+ tags: [
+ 'User Session',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the session is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The SessionInput schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Cookie',
+ in: 'header',
+ required: true,
+ description: 'Only needed for session\'s checking {sessionName}={sessionID}.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'X-CSRF-Token',
+ in: 'header',
+ required: true,
+ description: 'Only needed for session\'s checking. The {csrfToken} needed on all unsafe HTTP methods with session.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.SessionInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.SessionInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/SessionInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'Session already exists.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Session+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Session',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Session+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_CREATED => [
+ 'description' => 'Session is created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Session+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Session',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Session+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the authorization failed.',
+ ],
+ Response::HTTP_CONFLICT => [
+ 'description' => 'Error - header contained a session cookie but different user was authorized.',
+ ],
+ ],
+ ),
+)]
+/**
+ * @internal
+ */
+final class SessionCreateController extends SessionBaseController
+{
+ /**
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function createSessionAction(Request $request): RestValue
+ {
+ try {
+ $session = $request->getSession();
+ $csrfToken = $this->getCsrfToken();
+ $token = $this->securityTokenStorage->getToken();
+
+ if ($token === null) {
+ throw new UnauthorizedException('The current user is not authenticated.');
+ }
+
+ /** @var \Ibexa\Core\MVC\Symfony\Security\User $user */
+ $user = $token->getUser();
+
+ return new Values\UserSession(
+ $user->getAPIUser(),
+ $session->getName(),
+ $session->getId(),
+ $csrfToken,
+ !$token->hasAttribute('isFromSession')
+ );
+ } catch (Exceptions\UserConflictException $e) {
+ // Already logged in with another user, this will be converted to HTTP status 409
+ return new Values\Conflict();
+ } catch (AuthenticationException $e) {
+ throw new UnauthorizedException('Invalid login or password');
+ } catch (AccessDeniedException $e) {
+ throw new UnauthorizedException($e->getMessage());
+ }
+ }
+}
diff --git a/src/lib/Server/Controller/Session/SessionDeleteController.php b/src/lib/Server/Controller/Session/SessionDeleteController.php
new file mode 100644
index 000000000..4465a4bee
--- /dev/null
+++ b/src/lib/Server/Controller/Session/SessionDeleteController.php
@@ -0,0 +1,85 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'X-CSRF-Token',
+ in: 'header',
+ required: true,
+ description: 'The {csrfToken} needed on all unsafe HTTP methods with session.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'sessionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'OK - session deleted.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the session does not exist.',
+ ],
+ ],
+ ),
+)]
+/**
+ * @internal
+ */
+final class SessionDeleteController extends SessionBaseController
+{
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
+ */
+ public function deleteSessionAction(string $sessionId, Request $request): Values\DeletedUserSession|Response
+ {
+ /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
+ $session = $request->getSession();
+ if (!$session->isStarted() || $session->getId() !== $sessionId || !$this->hasStoredCsrfToken()) {
+ return $this->logout($request);
+ }
+
+ $this->checkCsrfToken($request);
+
+ return new Values\DeletedUserSession(
+ $this->logout($request)
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Session/SessionRefreshController.php b/src/lib/Server/Controller/Session/SessionRefreshController.php
new file mode 100644
index 000000000..4f421b2da
--- /dev/null
+++ b/src/lib/Server/Controller/Session/SessionRefreshController.php
@@ -0,0 +1,129 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Get the session\'s User information. Deprecated as of Ibexa DXP 4.6, use GET /user/sessions/current instead.',
+ tags: [
+ 'User Session',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Cookie',
+ in: 'header',
+ required: true,
+ description: '{sessionName}={sessionID}',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'X-CSRF-Token',
+ in: 'header',
+ required: true,
+ description: 'The {csrfToken} needed on all unsafe HTTP methods with session.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'sessionId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.Session+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Session',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Session+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/SessionWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the session does not exist.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+/**
+ * @internal
+ */
+final class SessionRefreshController extends SessionBaseController
+{
+ /**
+ * Refresh given session.
+ *
+ * @deprecated 5.0.0 The "SessionController::refreshSessionAction()" method is deprecated, will be removed in the next API version. Use SessionController::checkSessionAction() instead.
+ *
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
+ */
+ public function refreshSessionAction(string $sessionId, Request $request): Values\UserSession|Response
+ {
+ trigger_deprecation(
+ 'ibexa/rest',
+ '4.6.7',
+ sprintf('The %s() method is deprecated, will be removed in the next API version.', __METHOD__)
+ );
+
+ $session = $request->getSession();
+
+ if ($session === null || !$session->isStarted() || $session->getId() !== $sessionId || !$this->hasStoredCsrfToken()) {
+ return $this->logout($request);
+ }
+
+ $this->checkCsrfToken($request);
+ $currentUser = $this->userService->loadUser(
+ $this->permissionResolver->getCurrentUserReference()->getUserId()
+ );
+
+ return new Values\UserSession(
+ $currentUser,
+ $session->getName(),
+ $session->getId(),
+ $request->headers->get('X-CSRF-Token') ?? '',
+ false
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/SessionController.php b/src/lib/Server/Controller/SessionController.php
deleted file mode 100644
index 2f4208752..000000000
--- a/src/lib/Server/Controller/SessionController.php
+++ /dev/null
@@ -1,212 +0,0 @@
-getSession();
- $csrfToken = $this->getCsrfToken();
- $token = $this->securityTokenStorage->getToken();
-
- if ($token === null) {
- throw new UnauthorizedException('The current user is not authenticated.');
- }
-
- /** @var \Ibexa\Core\MVC\Symfony\Security\User $user */
- $user = $token->getUser();
-
- return new Values\UserSession(
- $user->getAPIUser(),
- $session->getName(),
- $session->getId(),
- $csrfToken,
- !$token->hasAttribute('isFromSession')
- );
- } catch (Exceptions\UserConflictException $e) {
- // Already logged in with another user, this will be converted to HTTP status 409
- return new Values\Conflict();
- } catch (AuthenticationException $e) {
- throw new UnauthorizedException('Invalid login or password');
- } catch (AccessDeniedException $e) {
- throw new UnauthorizedException($e->getMessage());
- }
- }
-
- public function checkSessionAction(Request $request): Values\UserSession|Response
- {
- $session = $request->getSession();
- if (!$session->isStarted()) {
- return $this->logout($request);
- }
-
- $currentUser = $this->userService->loadUser(
- $this->permissionResolver->getCurrentUserReference()->getUserId()
- );
-
- return new Values\UserSession(
- $currentUser,
- $session->getName(),
- $session->getId(),
- $this->getCsrfToken(),
- false
- );
- }
-
- /**
- * Refresh given session.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- */
- public function refreshSessionAction(string $sessionId, Request $request): Values\UserSession|Response
- {
- trigger_deprecation(
- 'ibexa/rest',
- '4.6.7',
- sprintf('The %s() method is deprecated, will be removed in the next API version.', __METHOD__)
- );
-
- $session = $request->getSession();
-
- if (!$session->isStarted() || $session->getId() !== $sessionId || !$this->hasStoredCsrfToken()) {
- return $this->logout($request);
- }
-
- $this->checkCsrfToken($request);
- $currentUser = $this->userService->loadUser(
- $this->permissionResolver->getCurrentUserReference()->getUserId()
- );
-
- return new Values\UserSession(
- $currentUser,
- $session->getName(),
- $session->getId(),
- $request->headers->get('X-CSRF-Token') ?? '',
- false
- );
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- */
- public function deleteSessionAction(string $sessionId, Request $request): Values\DeletedUserSession|Response
- {
- /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
- $session = $request->getSession();
- if (!$session->isStarted() || $session->getId() !== $sessionId || !$this->hasStoredCsrfToken()) {
- return $this->logout($request);
- }
-
- $this->checkCsrfToken($request);
-
- return new Values\DeletedUserSession(
- $this->logout($request)
- );
- }
-
- private function hasStoredCsrfToken(): bool
- {
- return $this->csrfTokenManager->hasToken($this->csrfTokenIntention);
- }
-
- /**
- * Checks the presence / validity of the CSRF token.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException if the token is missing or invalid
- */
- private function checkCsrfToken(Request $request): void
- {
- if (!$request->headers->has('X-CSRF-Token')) {
- throw $this->createInvalidCsrfTokenException($request);
- }
-
- $csrfToken = new CsrfToken(
- $this->csrfTokenIntention,
- $request->headers->get('X-CSRF-Token')
- );
-
- if (!$this->csrfTokenManager->isTokenValid($csrfToken)) {
- throw $this->createInvalidCsrfTokenException($request);
- }
- }
-
- private function getCsrfToken(): string
- {
- return $this->csrfTokenManager->getToken($this->csrfTokenIntention)->getValue();
- }
-
- private function createInvalidCsrfTokenException(Request $request): UnauthorizedException
- {
- return new UnauthorizedException('Missing or invalid CSRF token');
- }
-
- private function logout(Request $request): Response
- {
- $path = '/';
- $domain = null;
-
- $session = $this->configResolver->getParameter('session');
- if (array_key_exists('cookie_domain', $session)) {
- $domain = $session['cookie_domain'];
- }
-
- if (array_key_exists('cookie_path', $session)) {
- $path = $session['cookie_path'];
- }
-
- $response = new Response();
- $requestSession = $request->getSession();
-
- $response->headers->clearCookie(
- $requestSession->getName(),
- $path,
- $domain
- );
-
- $response->setStatusCode(Response::HTTP_NOT_FOUND);
- $requestSession->clear();
-
- return $response;
- }
-}
diff --git a/src/lib/Server/Controller/Trash/LocationTrashController.php b/src/lib/Server/Controller/Trash/LocationTrashController.php
new file mode 100644
index 000000000..2cf82e9a0
--- /dev/null
+++ b/src/lib/Server/Controller/Trash/LocationTrashController.php
@@ -0,0 +1,58 @@
+locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath),
+ );
+
+ $trashItem = $this->trashService->trash($location);
+
+ if ($trashItem === null) {
+ return new Values\NoContent();
+ }
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_trash_item',
+ ['trashItemId' => $trashItem->getId()],
+ ),
+ );
+ }
+
+ private function extractLocationIdFromPath(string $path): int
+ {
+ $pathParts = explode('/', $path);
+ $lastPart = array_pop($pathParts);
+
+ Assert::integerish($lastPart);
+
+ return (int)$lastPart;
+ }
+}
diff --git a/src/lib/Server/Controller/Trash/TrashEmptyController.php b/src/lib/Server/Controller/Trash/TrashEmptyController.php
new file mode 100644
index 000000000..30e3df6de
--- /dev/null
+++ b/src/lib/Server/Controller/Trash/TrashEmptyController.php
@@ -0,0 +1,57 @@
+ [
+ 'description' => 'No Content - Trash emptied.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to empty all items from Trash.',
+ ],
+ ],
+ ),
+)]
+class TrashEmptyController extends RestController
+{
+ public function __construct(
+ protected TrashService $trashService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Empties the trash.
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function emptyTrash()
+ {
+ $this->trashService->emptyTrash();
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Trash/TrashItemDeleteController.php b/src/lib/Server/Controller/Trash/TrashItemDeleteController.php
new file mode 100644
index 000000000..6f964de94
--- /dev/null
+++ b/src/lib/Server/Controller/Trash/TrashItemDeleteController.php
@@ -0,0 +1,72 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - item deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete the provided item.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The provided item does not exist in Trash.',
+ ],
+ ],
+ ),
+)]
+class TrashItemDeleteController extends RestController
+{
+ public function __construct(
+ protected TrashService $trashService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Deletes the given trash item.
+ *
+ * @param $trashItemId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteTrashItem($trashItemId)
+ {
+ $this->trashService->deleteTrashItem(
+ $this->trashService->loadTrashItem($trashItemId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/Trash/TrashItemListController.php b/src/lib/Server/Controller/Trash/TrashItemListController.php
new file mode 100644
index 000000000..000a38fd8
--- /dev/null
+++ b/src/lib/Server/Controller/Trash/TrashItemListController.php
@@ -0,0 +1,99 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the list of items in the Trash.',
+ 'content' => [
+ 'application/vnd.ibexa.api.Trash+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/Trash',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/trash/GET/Trash.xml.example',
+ ],
+ 'application/vnd.ibexa.api.Trash+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/TrashWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/trash/GET/Trash.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read the Trash.',
+ ],
+ ],
+ ),
+)]
+class TrashItemListController extends RestController
+{
+ public function __construct(
+ protected TrashService $trashService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Returns a list of all trash items.
+ *
+ * @return \Ibexa\Rest\Server\Values\Trash
+ */
+ public function loadTrashItems(Request $request)
+ {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
+
+ $query = new Query();
+ $query->offset = $offset >= 0 ? $offset : null;
+ $query->limit = $limit >= 0 ? $limit : null;
+
+ $trashItems = [];
+
+ foreach ($this->trashService->findTrashItems($query)->items as $trashItem) {
+ $trashItems[] = new Values\RestTrashItem(
+ $trashItem,
+ $this->locationService->getLocationChildCount($trashItem)
+ );
+ }
+
+ return new Values\Trash(
+ $trashItems,
+ $request->getPathInfo()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Trash/TrashItemLoadByIdController.php b/src/lib/Server/Controller/Trash/TrashItemLoadByIdController.php
new file mode 100644
index 000000000..2d363e0f3
--- /dev/null
+++ b/src/lib/Server/Controller/Trash/TrashItemLoadByIdController.php
@@ -0,0 +1,93 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'trashItemid',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.TrashItem+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/TrashItem',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.xml.example',
+ ],
+ 'application/vnd.ibexa.api.TrashItem+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/TrashItemWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/trash/trash_itemid/GET/TrashItem.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read the item in Trash.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - An item in Trash with the provided ID does not exist.',
+ ],
+ ],
+ ),
+)]
+class TrashItemLoadByIdController extends RestController
+{
+ public function __construct(
+ protected TrashService $trashService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Returns the trash item given by id.
+ *
+ * @param $trashItemId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestTrashItem
+ */
+ public function loadTrashItem($trashItemId)
+ {
+ return new Values\RestTrashItem(
+ $trashItem = $this->trashService->loadTrashItem($trashItemId),
+ $this->locationService->getLocationChildCount($trashItem)
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/Trash.php b/src/lib/Server/Controller/Trash/TrashItemRestoreController.php
similarity index 51%
rename from src/lib/Server/Controller/Trash.php
rename to src/lib/Server/Controller/Trash/TrashItemRestoreController.php
index a7b2b93ed..e7f33c073 100644
--- a/src/lib/Server/Controller/Trash.php
+++ b/src/lib/Server/Controller/Trash/TrashItemRestoreController.php
@@ -5,148 +5,26 @@
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
-namespace Ibexa\Rest\Server\Controller;
+namespace Ibexa\Rest\Server\Controller\Trash;
use Ibexa\Contracts\Core\Repository\Exceptions as ApiExceptions;
use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
use Ibexa\Contracts\Core\Repository\LocationService;
use Ibexa\Contracts\Core\Repository\TrashService;
-use Ibexa\Contracts\Core\Repository\Values\Content\Query;
use Ibexa\Rest\Message;
use Ibexa\Rest\Server\Controller as RestController;
use Ibexa\Rest\Server\Exceptions\ForbiddenException;
use Ibexa\Rest\Server\Values;
-use Ibexa\Rest\Value as RestValue;
use InvalidArgumentException;
use JMS\TranslationBundle\Annotation\Ignore;
use Symfony\Component\HttpFoundation\Request;
-use Webmozart\Assert\Assert;
-/**
- * Trash controller.
- */
-class Trash extends RestController
+class TrashItemRestoreController extends RestController
{
- /**
- * Trash service.
- *
- * @var \Ibexa\Contracts\Core\Repository\TrashService
- */
- protected $trashService;
-
- /**
- * Location service.
- *
- * @var \Ibexa\Contracts\Core\Repository\LocationService
- */
- protected $locationService;
-
- /**
- * Construct controller.
- *
- * @param \Ibexa\Contracts\Core\Repository\TrashService $trashService
- * @param \Ibexa\Contracts\Core\Repository\LocationService $locationService
- */
- public function __construct(TrashService $trashService, LocationService $locationService)
- {
- $this->trashService = $trashService;
- $this->locationService = $locationService;
- }
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
- */
- public function trashLocation(string $locationPath): RestValue
- {
- $location = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath),
- );
-
- $trashItem = $this->trashService->trash($location);
-
- if ($trashItem === null) {
- return new Values\NoContent();
- }
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_trash_item',
- ['trashItemId' => $trashItem->getId()],
- ),
- );
- }
-
- /**
- * Returns a list of all trash items.
- *
- * @return \Ibexa\Rest\Server\Values\Trash
- */
- public function loadTrashItems(Request $request)
- {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
-
- $query = new Query();
- $query->offset = $offset >= 0 ? $offset : null;
- $query->limit = $limit >= 0 ? $limit : null;
-
- $trashItems = [];
-
- foreach ($this->trashService->findTrashItems($query)->items as $trashItem) {
- $trashItems[] = new Values\RestTrashItem(
- $trashItem,
- $this->locationService->getLocationChildCount($trashItem)
- );
- }
-
- return new Values\Trash(
- $trashItems,
- $request->getPathInfo()
- );
- }
-
- /**
- * Returns the trash item given by id.
- *
- * @param $trashItemId
- *
- * @return \Ibexa\Rest\Server\Values\RestTrashItem
- */
- public function loadTrashItem($trashItemId)
- {
- return new Values\RestTrashItem(
- $trashItem = $this->trashService->loadTrashItem($trashItemId),
- $this->locationService->getLocationChildCount($trashItem)
- );
- }
-
- /**
- * Empties the trash.
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function emptyTrash()
- {
- $this->trashService->emptyTrash();
-
- return new Values\NoContent();
- }
-
- /**
- * Deletes the given trash item.
- *
- * @param $trashItemId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteTrashItem($trashItemId)
- {
- $this->trashService->deleteTrashItem(
- $this->trashService->loadTrashItem($trashItemId)
- );
-
- return new Values\NoContent();
+ public function __construct(
+ protected TrashService $trashService,
+ protected LocationService $locationService
+ ) {
}
/**
@@ -171,7 +49,7 @@ public function restoreTrashItem($trashItemId, Request $request)
if ($request->headers->has('Destination')) {
$locationPathParts = explode(
'/',
- $this->uriParser->getAttributeFromUri($request->headers->get('Destination'), 'locationPath')
+ $this->requestParser->parseHref($request->headers->get('Destination'), 'locationPath')
);
try {
@@ -245,14 +123,4 @@ public function restoreItem(int $trashItemId, Request $request): Values\Resource
)
);
}
-
- private function extractLocationIdFromPath(string $path): int
- {
- $pathParts = explode('/', $path);
- $lastPart = array_pop($pathParts);
-
- Assert::integerish($lastPart);
-
- return (int)$lastPart;
- }
}
diff --git a/src/lib/Server/Controller/URLAlias.php b/src/lib/Server/Controller/URLAlias.php
deleted file mode 100644
index 79b6244ae..000000000
--- a/src/lib/Server/Controller/URLAlias.php
+++ /dev/null
@@ -1,177 +0,0 @@
-urlAliasService = $urlAliasService;
- $this->locationService = $locationService;
- }
-
- /**
- * Returns the URL alias with the given ID.
- *
- * @param $urlAliasId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\URLAlias
- */
- public function loadURLAlias($urlAliasId)
- {
- return $this->urlAliasService->load($urlAliasId);
- }
-
- /**
- * Returns the list of global URL aliases.
- *
- * @return \Ibexa\Rest\Server\Values\URLAliasRefList
- */
- public function listGlobalURLAliases()
- {
- return new Values\URLAliasRefList(
- $this->urlAliasService->listGlobalAliases(),
- $this->router->generate('ibexa.rest.list_global_url_aliases')
- );
- }
-
- /**
- * Returns the list of URL aliases for a location.
- *
- * @param $locationPath
- *
- * @return \Ibexa\Rest\Server\Values\URLAliasRefList
- */
- public function listLocationURLAliases($locationPath, Request $request)
- {
- $locationPathParts = explode('/', $locationPath);
-
- $location = $this->locationService->loadLocation(
- array_pop($locationPathParts)
- );
-
- $custom = !($request->query->has('custom') && $request->query->get('custom') === 'false');
-
- return new Values\CachedValue(
- new Values\URLAliasRefList(
- $this->urlAliasService->listLocationAliases($location, $custom),
- $request->getPathInfo()
- ),
- ['locationId' => $location->id]
- );
- }
-
- /**
- * Creates a new URL alias.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedURLAlias
- */
- public function createURLAlias(Request $request)
- {
- $urlAliasCreate = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- if ($urlAliasCreate['_type'] === 'LOCATION') {
- $locationPathParts = explode(
- '/',
- $this->uriParser->getAttributeFromUri($urlAliasCreate['location']['_href'], 'locationPath')
- );
-
- $location = $this->locationService->loadLocation(
- array_pop($locationPathParts)
- );
-
- try {
- $createdURLAlias = $this->urlAliasService->createUrlAlias(
- $location,
- $urlAliasCreate['path'],
- $urlAliasCreate['languageCode'],
- $urlAliasCreate['forward'],
- $urlAliasCreate['alwaysAvailable']
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- } else {
- try {
- $createdURLAlias = $this->urlAliasService->createGlobalUrlAlias(
- $urlAliasCreate['resource'],
- $urlAliasCreate['path'],
- $urlAliasCreate['languageCode'],
- $urlAliasCreate['forward'],
- $urlAliasCreate['alwaysAvailable']
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
- }
-
- return new Values\CreatedURLAlias(
- [
- 'urlAlias' => $createdURLAlias,
- ]
- );
- }
-
- /**
- * The given URL alias is deleted.
- *
- * @param $urlAliasId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteURLAlias($urlAliasId)
- {
- $this->urlAliasService->removeAliases(
- [
- $this->urlAliasService->load($urlAliasId),
- ]
- );
-
- return new Values\NoContent();
- }
-}
diff --git a/src/lib/Server/Controller/URLAlias/URLAliasCreateController.php b/src/lib/Server/Controller/URLAlias/URLAliasCreateController.php
new file mode 100644
index 000000000..6b80a7c1a
--- /dev/null
+++ b/src/lib/Server/Controller/URLAlias/URLAliasCreateController.php
@@ -0,0 +1,164 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a URL alias.',
+ tags: [
+ 'Url Alias',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the created URL alias is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The URL alias input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UrlAliasCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlAliasCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/POST/UrlAliasCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'URL alias created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlAlias+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAlias',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlAlias+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create a URL alias.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A URL alias with the same identifier already exists.',
+ ],
+ ],
+ ),
+)]
+class URLAliasCreateController extends RestController
+{
+ public function __construct(
+ protected URLAliasService $urlAliasService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Creates a new URL alias.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedURLAlias
+ */
+ public function createURLAlias(Request $request)
+ {
+ $urlAliasCreate = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ if ($urlAliasCreate['_type'] === 'LOCATION') {
+ $locationPathParts = explode(
+ '/',
+ $this->requestParser->parseHref($urlAliasCreate['location']['_href'], 'locationPath')
+ );
+
+ $location = $this->locationService->loadLocation(
+ array_pop($locationPathParts)
+ );
+
+ try {
+ $createdURLAlias = $this->urlAliasService->createUrlAlias(
+ $location,
+ $urlAliasCreate['path'],
+ $urlAliasCreate['languageCode'],
+ $urlAliasCreate['forward'],
+ $urlAliasCreate['alwaysAvailable']
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ } else {
+ try {
+ $createdURLAlias = $this->urlAliasService->createGlobalUrlAlias(
+ $urlAliasCreate['resource'],
+ $urlAliasCreate['path'],
+ $urlAliasCreate['languageCode'],
+ $urlAliasCreate['forward'],
+ $urlAliasCreate['alwaysAvailable']
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+ }
+
+ return new Values\CreatedURLAlias(
+ [
+ 'urlAlias' => $createdURLAlias,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/URLAlias/URLAliasDeleteController.php b/src/lib/Server/Controller/URLAlias/URLAliasDeleteController.php
new file mode 100644
index 000000000..189bbd3fe
--- /dev/null
+++ b/src/lib/Server/Controller/URLAlias/URLAliasDeleteController.php
@@ -0,0 +1,74 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - URL alias deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete a URL alias.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The URL alias does not exist.',
+ ],
+ ],
+ ),
+)]
+class URLAliasDeleteController extends RestController
+{
+ public function __construct(
+ protected URLAliasService $urlAliasService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * The given URL alias is deleted.
+ *
+ * @param $urlAliasId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteURLAlias($urlAliasId)
+ {
+ $this->urlAliasService->removeAliases(
+ [
+ $this->urlAliasService->load($urlAliasId),
+ ]
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/URLAlias/URLAliasListGlobalController.php b/src/lib/Server/Controller/URLAlias/URLAliasListGlobalController.php
new file mode 100644
index 000000000..b872ac1cd
--- /dev/null
+++ b/src/lib/Server/Controller/URLAlias/URLAliasListGlobalController.php
@@ -0,0 +1,81 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the list of URL aliases.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlAliasRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlAliasRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read URL aliases.',
+ ],
+ ],
+ ),
+)]
+class URLAliasListGlobalController extends RestController
+{
+ public function __construct(
+ protected URLAliasService $urlAliasService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Returns the list of global URL aliases.
+ *
+ * @return \Ibexa\Rest\Server\Values\URLAliasRefList
+ */
+ public function listGlobalURLAliases()
+ {
+ return new Values\URLAliasRefList(
+ $this->urlAliasService->listGlobalAliases(),
+ $this->router->generate('ibexa.rest.list_global_url_aliases')
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/URLAlias/URLAliasListLocationController.php b/src/lib/Server/Controller/URLAlias/URLAliasListLocationController.php
new file mode 100644
index 000000000..3773603aa
--- /dev/null
+++ b/src/lib/Server/Controller/URLAlias/URLAliasListLocationController.php
@@ -0,0 +1,105 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the list of URL aliases.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlAliasRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/GET/UrlAliasRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlAliasRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasRefListWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The user has no permission to read URL aliases.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The Location was not found.',
+ ],
+ ],
+ ),
+)]
+class URLAliasListLocationController extends RestController
+{
+ public function __construct(
+ protected URLAliasService $urlAliasService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Returns the list of URL aliases for a location.
+ *
+ * @param $locationPath
+ *
+ * @return \Ibexa\Rest\Server\Values\URLAliasRefList
+ */
+ public function listLocationURLAliases($locationPath, Request $request)
+ {
+ $locationPathParts = explode('/', $locationPath);
+
+ $location = $this->locationService->loadLocation(
+ array_pop($locationPathParts)
+ );
+
+ $custom = !($request->query->has('custom') && $request->query->get('custom') === 'false');
+
+ return new Values\CachedValue(
+ new Values\URLAliasRefList(
+ $this->urlAliasService->listLocationAliases($location, $custom),
+ $request->getPathInfo()
+ ),
+ ['locationId' => $location->id]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/URLAlias/URLAliasLoadByIdController.php b/src/lib/Server/Controller/URLAlias/URLAliasLoadByIdController.php
new file mode 100644
index 000000000..76ffc9c29
--- /dev/null
+++ b/src/lib/Server/Controller/URLAlias/URLAliasLoadByIdController.php
@@ -0,0 +1,90 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'urlAliasId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the URL alias.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlAlias+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAlias',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlAlias+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlAliasWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlaliases/url_alias_id/GET/UrlAlias.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read URL aliases.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The URL alias does not exist.',
+ ],
+ ],
+ ),
+)]
+class URLAliasLoadByIdController extends RestController
+{
+ public function __construct(
+ protected URLAliasService $urlAliasService,
+ protected LocationService $locationService
+ ) {
+ }
+
+ /**
+ * Returns the URL alias with the given ID.
+ *
+ * @param $urlAliasId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\URLAlias
+ */
+ public function loadURLAlias($urlAliasId)
+ {
+ return $this->urlAliasService->load($urlAliasId);
+ }
+}
diff --git a/src/lib/Server/Controller/URLWildcard.php b/src/lib/Server/Controller/URLWildcard.php
deleted file mode 100644
index b02c319a0..000000000
--- a/src/lib/Server/Controller/URLWildcard.php
+++ /dev/null
@@ -1,113 +0,0 @@
-urlWildcardService = $urlWildcardService;
- }
-
- /**
- * Returns the URL wildcard with the given id.
- *
- * @param $urlWildcardId
- *
- * @return \Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard
- */
- public function loadURLWildcard($urlWildcardId)
- {
- return $this->urlWildcardService->load($urlWildcardId);
- }
-
- /**
- * Returns the list of URL wildcards.
- *
- * @return \Ibexa\Rest\Server\Values\URLWildcardList
- */
- public function listURLWildcards()
- {
- return new Values\URLWildcardList(
- $this->urlWildcardService->loadAll()
- );
- }
-
- /**
- * Creates a new URL wildcard.
- *
- * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
- *
- * @return \Ibexa\Rest\Server\Values\CreatedURLWildcard
- */
- public function createURLWildcard(Request $request)
- {
- $urlWildcardCreate = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- $createdURLWildcard = $this->urlWildcardService->create(
- $urlWildcardCreate['sourceUrl'],
- $urlWildcardCreate['destinationUrl'],
- $urlWildcardCreate['forward']
- );
- } catch (InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- return new Values\CreatedURLWildcard(
- [
- 'urlWildcard' => $createdURLWildcard,
- ]
- );
- }
-
- /**
- * The given URL wildcard is deleted.
- *
- * @param $urlWildcardId
- *
- * @return \Ibexa\Rest\Server\Values\NoContent
- */
- public function deleteURLWildcard($urlWildcardId)
- {
- $this->urlWildcardService->remove(
- $this->urlWildcardService->load($urlWildcardId)
- );
-
- return new Values\NoContent();
- }
-}
diff --git a/src/lib/Server/Controller/URLWildcard/URLWildcardCreateController.php b/src/lib/Server/Controller/URLWildcard/URLWildcardCreateController.php
new file mode 100644
index 000000000..d009e5197
--- /dev/null
+++ b/src/lib/Server/Controller/URLWildcard/URLWildcardCreateController.php
@@ -0,0 +1,137 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new URL wildcard.',
+ tags: [
+ 'Url Wildcard',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new URL wildcard is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The URL Wildcard input schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UrlWildcardCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlWildcardCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/POST/UrlWildcardCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'URL wildcard created.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlWildcard+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcard',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlWildcard+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - The input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to create a URL wildcard.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - A URL wildcard with the same identifier already exists.',
+ ],
+ ],
+ ),
+)]
+class URLWildcardCreateController extends RestController
+{
+ public function __construct(
+ protected URLWildcardService $urlWildcardService
+ ) {
+ }
+
+ /**
+ * Creates a new URL wildcard.
+ *
+ * @throws \Ibexa\Rest\Server\Exceptions\ForbiddenException
+ *
+ * @return \Ibexa\Rest\Server\Values\CreatedURLWildcard
+ */
+ public function createURLWildcard(Request $request)
+ {
+ $urlWildcardCreate = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $createdURLWildcard = $this->urlWildcardService->create(
+ $urlWildcardCreate['sourceUrl'],
+ $urlWildcardCreate['destinationUrl'],
+ $urlWildcardCreate['forward']
+ );
+ } catch (InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ return new Values\CreatedURLWildcard(
+ [
+ 'urlWildcard' => $createdURLWildcard,
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/URLWildcard/URLWildcardDeleteController.php b/src/lib/Server/Controller/URLWildcard/URLWildcardDeleteController.php
new file mode 100644
index 000000000..dd1ad8ce0
--- /dev/null
+++ b/src/lib/Server/Controller/URLWildcard/URLWildcardDeleteController.php
@@ -0,0 +1,70 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content - URL wildcard deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to delete a URL wildcard.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The URL wildcard does not exist.',
+ ],
+ ],
+ ),
+)]
+class URLWildcardDeleteController extends RestController
+{
+ public function __construct(
+ protected URLWildcardService $urlWildcardService
+ ) {
+ }
+
+ /**
+ * The given URL wildcard is deleted.
+ *
+ * @param $urlWildcardId
+ *
+ * @return \Ibexa\Rest\Server\Values\NoContent
+ */
+ public function deleteURLWildcard($urlWildcardId)
+ {
+ $this->urlWildcardService->remove(
+ $this->urlWildcardService->load($urlWildcardId)
+ );
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/URLWildcard/URLWildcardListController.php b/src/lib/Server/Controller/URLWildcard/URLWildcardListController.php
new file mode 100644
index 000000000..32daa45dc
--- /dev/null
+++ b/src/lib/Server/Controller/URLWildcard/URLWildcardListController.php
@@ -0,0 +1,78 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns a list of URL wildcards.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlWildcardList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlWildcardList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/GET/UrlWildcardList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user has no permission to read URL wildcards.',
+ ],
+ ],
+ ),
+)]
+class URLWildcardListController extends RestController
+{
+ public function __construct(
+ protected URLWildcardService $urlWildcardService
+ ) {
+ }
+
+ /**
+ * Returns the list of URL wildcards.
+ *
+ * @return \Ibexa\Rest\Server\Values\URLWildcardList
+ */
+ public function listURLWildcards()
+ {
+ return new Values\URLWildcardList(
+ $this->urlWildcardService->loadAll()
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/URLWildcard/URLWildcardLoadByIdController.php b/src/lib/Server/Controller/URLWildcard/URLWildcardLoadByIdController.php
new file mode 100644
index 000000000..69f272248
--- /dev/null
+++ b/src/lib/Server/Controller/URLWildcard/URLWildcardLoadByIdController.php
@@ -0,0 +1,88 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'wildcardId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - returns the URL wildcard.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UrlWildcard+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcard',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UrlWildcard+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UrlWildcardWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/urlwildcards/wildcard_id/GET/UrlWildcard.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - The user is not authorized to read URL wildcards.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - The URL wildcard does not exist.',
+ ],
+ ],
+ ),
+)]
+class URLWildcardLoadByIdController extends RestController
+{
+ public function __construct(
+ protected URLWildcardService $urlWildcardService
+ ) {
+ }
+
+ /**
+ * Returns the URL wildcard with the given id.
+ *
+ * @param $urlWildcardId
+ *
+ * @return \Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard
+ */
+ public function loadURLWildcard($urlWildcardId)
+ {
+ return $this->urlWildcardService->load($urlWildcardId);
+ }
+}
diff --git a/src/lib/Server/Controller/User.php b/src/lib/Server/Controller/User.php
deleted file mode 100644
index 18ca7d384..000000000
--- a/src/lib/Server/Controller/User.php
+++ /dev/null
@@ -1,947 +0,0 @@
-userService = $userService;
- $this->roleService = $roleService;
- $this->contentService = $contentService;
- $this->contentTypeService = $contentTypeService;
- $this->locationService = $locationService;
- $this->sectionService = $sectionService;
- $this->repository = $repository;
- $this->permissionResolver = $permissionResolver;
- $this->relationListFacade = $relationListFacade;
- }
-
- /**
- * Redirects to the root user group.
- */
- public function loadRootUserGroup(): Values\PermanentRedirect
- {
- //@todo Replace hardcoded value with one loaded from settings
- return new Values\PermanentRedirect(
- $this->router->generate('ibexa.rest.load_user_group', ['groupPath' => '/1/5'])
- );
- }
-
- /**
- * Loads a user group for the given path.
- */
- public function loadUserGroup(string $groupPath): RestValue
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- if (trim($userGroupLocation->pathString, '/') !== $groupPath) {
- throw new NotFoundException(
- "Could not find a Location with path string $groupPath"
- );
- }
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId,
- Language::ALL
- );
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- return new Values\CachedValue(
- new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- ),
- ['locationId' => $userGroupLocation->id]
- );
- }
-
- public function loadUser(int $userId): RestValue
- {
- $user = $this->userService->loadUser($userId, Language::ALL);
-
- $userContentInfo = $user->getVersionInfo()->getContentInfo();
- $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
-
- try {
- $userMainLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
- $relations = $this->relationListFacade->getRelations($user->getVersionInfo());
- } catch (UnauthorizedException $e) {
- // TODO: Hack for special case to allow current logged in user to load him/here self (but not relations)
- if ($user->id == $this->permissionResolver->getCurrentUserReference()->getUserId()) {
- $userMainLocation = $this->repository->sudo(
- function () use ($userContentInfo) {
- return $this->locationService->loadLocation($userContentInfo->mainLocationId);
- }
- );
- // user may not have permissions to read related content, for security reasons do not use sudo().
- $relations = [];
- } else {
- throw $e;
- }
- }
-
- return new Values\CachedValue(
- new Values\RestUser(
- $user,
- $contentType,
- $userContentInfo,
- $userMainLocation,
- iterator_to_array($relations)
- ),
- ['locationId' => $userContentInfo->mainLocationId]
- );
- }
-
- /**
- * @see \Symfony\Component\Security\Http\Controller\UserValueResolver
- */
- public function redirectToCurrentUser(?UserInterface $user): Values\TemporaryRedirect
- {
- if ($user === null) {
- throw new UnauthorizedHttpException('', 'Not logged in.');
- }
-
- $userReference = $this->permissionResolver->getCurrentUserReference();
-
- return new Values\TemporaryRedirect(
- $this->router->generate('ibexa.rest.load_user', ['userId' => $userReference->getUserId()])
- );
- }
-
- /**
- * Create a new user group under the given parent
- * To create a top level group use /user/groups/1/5/subgroups.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function createUserGroup(string $groupPath, Request $request): Values\CreatedUserGroup
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $createdUserGroup = $this->userService->createUserGroup(
- $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- ),
- $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- )
- );
-
- $createdContentInfo = $createdUserGroup->getVersionInfo()->getContentInfo();
- $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
-
- return new Values\CreatedUserGroup(
- [
- 'userGroup' => new Values\RestUserGroup(
- $createdUserGroup,
- $contentType,
- $createdContentInfo,
- $createdLocation,
- iterator_to_array($this->relationListFacade->getRelations($createdUserGroup->getVersionInfo()))
- ),
- ]
- );
- }
-
- /**
- * Create a new user group in the given group.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function createUser(string $groupPath, Request $request): Values\CreatedUser
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
- $userGroup = $this->userService->loadUserGroup($userGroupLocation->contentId);
-
- $userCreateStruct = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent()
- )
- );
-
- try {
- $createdUser = $this->userService->createUser($userCreateStruct, [$userGroup]);
- } catch (ApiExceptions\InvalidArgumentException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage());
- }
-
- $createdContentInfo = $createdUser->getVersionInfo()->getContentInfo();
- $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
-
- return new Values\CreatedUser(
- [
- 'user' => new Values\RestUser(
- $createdUser,
- $contentType,
- $createdContentInfo,
- $createdLocation,
- iterator_to_array($this->relationListFacade->getRelations($createdUser->getVersionInfo()))
- ),
- ]
- );
- }
-
- public function updateUserGroup(string $groupPath, Request $request): Values\RestUserGroup
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- // @todo Needs refactoring! Temporary solution so parser has access to URL
- 'Url' => $request->getPathInfo(),
- ],
- $request->getContent()
- )
- );
-
- if ($updateStruct->sectionId !== null) {
- $section = $this->sectionService->loadSection($updateStruct->sectionId);
- $this->sectionService->assignSection(
- $userGroup->getVersionInfo()->getContentInfo(),
- $section
- );
- }
-
- $updatedGroup = $this->userService->updateUserGroup($userGroup, $updateStruct->userGroupUpdateStruct);
- $contentType = $this->contentTypeService->loadContentType(
- $updatedGroup->getVersionInfo()->getContentInfo()->contentTypeId
- );
-
- return new Values\RestUserGroup(
- $updatedGroup,
- $contentType,
- $updatedGroup->getVersionInfo()->getContentInfo(),
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($updatedGroup->getVersionInfo()))
- );
- }
-
- public function updateUser(int $userId, Request $request): Values\RestUser
- {
- $user = $this->userService->loadUser($userId);
-
- $updateStruct = $this->inputDispatcher->parse(
- new Message(
- [
- 'Content-Type' => $request->headers->get('Content-Type'),
- // @todo Needs refactoring! Temporary solution so parser has access to URL
- 'Url' => $request->getPathInfo(),
- ],
- $request->getContent()
- )
- );
-
- if ($updateStruct->sectionId !== null) {
- $section = $this->sectionService->loadSection($updateStruct->sectionId);
- $this->sectionService->assignSection(
- $user->getVersionInfo()->getContentInfo(),
- $section
- );
- }
-
- $updatedUser = $this->userService->updateUser($user, $updateStruct->userUpdateStruct);
- $updatedContentInfo = $updatedUser->getVersionInfo()->getContentInfo();
- $mainLocation = $this->locationService->loadLocation($updatedContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($updatedContentInfo->contentTypeId);
-
- return new Values\RestUser(
- $updatedUser,
- $contentType,
- $updatedContentInfo,
- $mainLocation,
- iterator_to_array($this->relationListFacade->getRelations($updatedUser->getVersionInfo()))
- );
- }
-
- /**
- * Given user group is deleted.
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function deleteUserGroup(string $groupPath): Values\NoContent
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- // Load one user to see if user group is empty or not
- $users = $this->userService->loadUsersOfUserGroup($userGroup, 0, 1);
- if (!empty($users)) {
- throw new Exceptions\ForbiddenException('Cannot delete non-empty User Groups');
- }
-
- $this->userService->deleteUserGroup($userGroup);
-
- return new Values\NoContent();
- }
-
- /**
- * Given user is deleted.
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function deleteUser(int $userId): Values\NoContent
- {
- $user = $this->userService->loadUser($userId);
-
- if ($user->id == $this->permissionResolver->getCurrentUserReference()->getUserId()) {
- throw new Exceptions\ForbiddenException('Cannot delete the currently authenticated User');
- }
-
- $this->userService->deleteUser($user);
-
- return new Values\NoContent();
- }
-
- /**
- * Loads users.
- */
- public function loadUsers(Request $request): RestValue
- {
- $restUsers = [];
-
- try {
- if ($request->query->has('roleId')) {
- $restUsers = $this->loadUsersAssignedToRole(
- $this->uriParser->getAttributeFromUri((string)$request->query->get('roleId'), 'roleId')
- );
- } elseif ($request->query->has('remoteId')) {
- $restUsers = [
- $this->buildRestUserObject(
- $this->userService->loadUser(
- $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'))->id,
- Language::ALL
- )
- ),
- ];
- } elseif ($request->query->has('login')) {
- $restUsers = [
- $this->buildRestUserObject(
- $this->userService->loadUserByLogin((string)$request->query->get('login'), Language::ALL)
- ),
- ];
- } elseif ($request->query->has('email')) {
- foreach ($this->userService->loadUsersByEmail((string)$request->query->get('email'), Language::ALL) as $user) {
- $restUsers[] = $this->buildRestUserObject($user);
- }
- }
- } catch (ApiExceptions\UnauthorizedException $e) {
- $restUsers = [];
- }
-
- if (empty($restUsers)) {
- throw new NotFoundException('Could not find Users with the given filter');
- }
-
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.userlist') {
- return new Values\UserList($restUsers, $request->getPathInfo());
- }
-
- return new Values\UserRefList($restUsers, $request->getPathInfo());
- }
-
- public function verifyUsers(Request $request): Values\OK
- {
- // We let the NotFoundException loadUsers throws if there are no results pass.
- $this->loadUsers($request)->users;
-
- return new Values\OK();
- }
-
- /**
- * Loads a list of users assigned to role.
- *
- * @param mixed $roleId
- *
- * @return \Ibexa\Rest\Server\Values\RestUser[]
- */
- public function loadUsersAssignedToRole($roleId): array
- {
- $role = $this->roleService->loadRole($roleId);
- $roleAssignments = $this->roleService->getRoleAssignments($role);
-
- $restUsers = [];
-
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment instanceof UserRoleAssignment) {
- $restUsers[] = $this->buildRestUserObject($roleAssignment->getUser());
- }
- }
-
- return $restUsers;
- }
-
- private function buildRestUserObject(RepositoryUser $user): Values\RestUser
- {
- return new Values\RestUser(
- $user,
- $this->contentTypeService->loadContentType($user->contentInfo->contentTypeId),
- $user->contentInfo,
- $this->locationService->loadLocation($user->contentInfo->mainLocationId),
- iterator_to_array($this->relationListFacade->getRelations($user->getVersionInfo()))
- );
- }
-
- /**
- * Loads user groups.
- */
- public function loadUserGroups(Request $request): RestValue
- {
- $restUserGroups = [];
- if ($request->query->has('id')) {
- $userGroup = $this->userService->loadUserGroup((int)$request->query->get('id'), Language::ALL);
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $userGroupMainLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- $restUserGroups = [
- new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupMainLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- ),
- ];
- } elseif ($request->query->has('roleId')) {
- $restUserGroups = $this->loadUserGroupsAssignedToRole($request->query->get('roleId'));
- } elseif ($request->query->has('remoteId')) {
- $restUserGroups = [
- $this->loadUserGroupByRemoteId($request),
- ];
- }
-
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.usergrouplist') {
- return new Values\UserGroupList($restUserGroups, $request->getPathInfo());
- }
-
- return new Values\UserGroupRefList($restUserGroups, $request->getPathInfo());
- }
-
- /**
- * Loads a user group by its remote ID.
- */
- public function loadUserGroupByRemoteId(Request $request): Values\RestUserGroup
- {
- $contentInfo = $this->contentService->loadContentInfoByRemoteId((string)$request->query->get('remoteId'));
- $userGroup = $this->userService->loadUserGroup($contentInfo->id, Language::ALL);
- $userGroupLocation = $this->locationService->loadLocation($contentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($contentInfo->contentTypeId);
-
- return new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $contentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- );
- }
-
- /**
- * Loads a list of user groups assigned to role.
- *
- * @param mixed $roleId
- *
- * @return \Ibexa\Rest\Server\Values\RestUserGroup[]
- */
- public function loadUserGroupsAssignedToRole($roleId): array
- {
- $role = $this->roleService->loadRole($roleId);
- $roleAssignments = $this->roleService->getRoleAssignments($role);
-
- $restUserGroups = [];
-
- foreach ($roleAssignments as $roleAssignment) {
- if ($roleAssignment instanceof UserGroupRoleAssignment) {
- $userGroup = $roleAssignment->getUserGroup();
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- $restUserGroups[] = new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- );
- }
- }
-
- return $restUserGroups;
- }
-
- /**
- * Loads drafts assigned to user.
- */
- public function loadUserDrafts(int $userId, Request $request): Values\VersionList
- {
- $contentDrafts = $this->contentService->loadContentDraftList(
- $this->userService->loadUser($userId)
- );
-
- return new Values\VersionList(
- array_filter(array_map(
- static fn (ContentDraftListItemInterface $draftListItem): ?VersionInfo => $draftListItem->getVersionInfo(),
- $contentDrafts->items
- )),
- $request->getPathInfo()
- );
- }
-
- /**
- * Moves the user group to another parent.
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function moveUserGroup(string $groupPath, Request $request): Values\ResourceCreated
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- $locationPath = $this->uriParser->getAttributeFromUri(
- (string)$request->headers->get('Destination'),
- 'groupPath'
- );
-
- try {
- $destinationGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($locationPath)
- );
- } catch (ApiExceptions\NotFoundException $e) {
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- try {
- $destinationGroup = $this->userService->loadUserGroup($destinationGroupLocation->contentId);
- } catch (ApiExceptions\NotFoundException $e) {
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- $this->userService->moveUserGroup($userGroup, $destinationGroup);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_user_group',
- [
- 'groupPath' => trim($destinationGroupLocation->pathString, '/') . '/' . $userGroupLocation->id,
- ]
- )
- );
- }
-
- /**
- * @throws \Ibexa\Contracts\Rest\Exceptions\ForbiddenException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function moveGroup(string $groupPath, Request $request): Values\ResourceCreated
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId,
- );
-
- try {
- /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $destinationLocation */
- $destinationLocation = $this->inputDispatcher->parse(
- new Message(
- ['Content-Type' => $request->headers->get('Content-Type')],
- $request->getContent(),
- ),
- );
- } catch (ApiExceptions\NotFoundException $e) {
- throw new ForbiddenException(/** @Ignore */ $e->getMessage(), 1, $e);
- }
-
- $destinationGroup = $this->userService->loadUserGroup(
- $destinationLocation->getContent()->getId(),
- );
-
- $this->userService->moveUserGroup($userGroup, $destinationGroup);
-
- return new Values\ResourceCreated(
- $this->router->generate(
- 'ibexa.rest.load_user_group',
- [
- 'groupPath' => trim($destinationLocation->pathString, '/')
- . '/'
- . $userGroupLocation->getId(),
- ],
- )
- );
- }
-
- /**
- * Returns a list of the sub groups.
- */
- public function loadSubUserGroups(string $groupPath, Request $request): RestValue
- {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
-
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- $subGroups = $this->userService->loadSubUserGroups(
- $userGroup,
- $offset >= 0 ? $offset : 0,
- $limit >= 0 ? $limit : 25,
- Language::ALL
- );
-
- $restUserGroups = [];
- foreach ($subGroups as $subGroup) {
- $subGroupContentInfo = $subGroup->getVersionInfo()->getContentInfo();
- $subGroupLocation = $this->locationService->loadLocation($subGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($subGroupContentInfo->contentTypeId);
-
- $restUserGroups[] = new Values\RestUserGroup(
- $subGroup,
- $contentType,
- $subGroupContentInfo,
- $subGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($subGroup->getVersionInfo()))
- );
- }
-
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.usergrouplist') {
- return new Values\CachedValue(
- new Values\UserGroupList($restUserGroups, $request->getPathInfo()),
- ['locationId' => $userGroupLocation->id]
- );
- }
-
- return new Values\CachedValue(
- new Values\UserGroupRefList($restUserGroups, $request->getPathInfo()),
- ['locationId' => $userGroupLocation->id]
- );
- }
-
- /**
- * Returns a list of user groups the user belongs to.
- * The returned list includes the resources for unassigning
- * a user group if the user is in multiple groups.
- */
- public function loadUserGroupsOfUser(int $userId, Request $request): RestValue
- {
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
-
- $user = $this->userService->loadUser($userId);
- $userGroups = $this->userService->loadUserGroupsOfUser(
- $user,
- $offset >= 0 ? $offset : 0,
- $limit >= 0 ? $limit : 25,
- Language::ALL
- );
-
- $restUserGroups = [];
- foreach ($userGroups as $userGroup) {
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- $restUserGroups[] = new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- );
- }
-
- return new Values\CachedValue(
- new Values\UserGroupRefList($restUserGroups, $request->getPathInfo(), $userId),
- ['locationId' => $user->contentInfo->mainLocationId]
- );
- }
-
- /**
- * Loads the users of the group with the given path.
- */
- public function loadUsersFromGroup(string $groupPath, Request $request): RestValue
- {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($groupPath)
- );
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
- $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
-
- $users = $this->userService->loadUsersOfUserGroup(
- $userGroup,
- $offset >= 0 ? $offset : 0,
- $limit >= 0 ? $limit : 25,
- Language::ALL
- );
-
- $restUsers = [];
- foreach ($users as $user) {
- $userContentInfo = $user->getVersionInfo()->getContentInfo();
- $userLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
-
- $restUsers[] = new Values\RestUser(
- $user,
- $contentType,
- $userContentInfo,
- $userLocation,
- iterator_to_array($this->relationListFacade->getRelations($user->getVersionInfo()))
- );
- }
-
- if ($this->getMediaType($request) === 'application/vnd.ibexa.api.userlist') {
- return new Values\CachedValue(
- new Values\UserList($restUsers, $request->getPathInfo()),
- ['locationId' => $userGroupLocation->id]
- );
- }
-
- return new Values\CachedValue(
- new Values\UserRefList($restUsers, $request->getPathInfo()),
- ['locationId' => $userGroupLocation->id]
- );
- }
-
- /**
- * Unassigns the user from a user group.
- *
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function unassignUserFromUserGroup(int $userId, string $groupPath): Values\UserGroupRefList
- {
- $user = $this->userService->loadUser($userId);
- $userGroupLocation = $this->locationService->loadLocation((int)trim($groupPath, '/'));
-
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
-
- try {
- $this->userService->unAssignUserFromUserGroup($user, $userGroup);
- } catch (ApiExceptions\InvalidArgumentException $e) {
- // User is not in the group
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- $userGroups = $this->userService->loadUserGroupsOfUser($user);
- $restUserGroups = [];
- foreach ($userGroups as $userGroup) {
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- $restUserGroups[] = new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- );
- }
-
- return new Values\UserGroupRefList(
- $restUserGroups,
- $this->router->generate(
- 'ibexa.rest.load_user_groups_of_user',
- ['userId' => $userId]
- ),
- $userId
- );
- }
-
- /**
- * Assigns the user to a user group.
- *
- * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
- * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
- */
- public function assignUserToUserGroup(int $userId, Request $request): Values\UserGroupRefList
- {
- $user = $this->userService->loadUser($userId);
-
- try {
- $userGroupLocation = $this->locationService->loadLocation(
- $this->extractLocationIdFromPath($request->query->get('group'))
- );
- } catch (ApiExceptions\NotFoundException $e) {
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- try {
- $userGroup = $this->userService->loadUserGroup(
- $userGroupLocation->contentId
- );
- } catch (ApiExceptions\NotFoundException $e) {
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- try {
- $this->userService->assignUserToUserGroup($user, $userGroup);
- } catch (ApiExceptions\NotFoundException $e) {
- throw new Exceptions\ForbiddenException($e->getMessage());
- }
-
- $userGroups = $this->userService->loadUserGroupsOfUser($user);
- $restUserGroups = [];
- foreach ($userGroups as $userGroup) {
- $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
- $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
- $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
-
- $restUserGroups[] = new Values\RestUserGroup(
- $userGroup,
- $contentType,
- $userGroupContentInfo,
- $userGroupLocation,
- iterator_to_array($this->relationListFacade->getRelations($userGroup->getVersionInfo()))
- );
- }
-
- return new Values\UserGroupRefList(
- $restUserGroups,
- $this->router->generate(
- 'ibexa.rest.load_user_groups_of_user',
- ['userId' => $userId]
- ),
- $userId
- );
- }
-
- /**
- * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
- */
- private function extractLocationIdFromPath(string $path): int
- {
- $pathParts = explode('/', $path);
-
- return (int)array_pop($pathParts);
- }
-}
diff --git a/src/lib/Server/Controller/User/UserAssignToUserGroupController.php b/src/lib/Server/Controller/User/UserAssignToUserGroupController.php
new file mode 100644
index 000000000..babfdc580
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserAssignToUserGroupController.php
@@ -0,0 +1,163 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Assigns the User to a User Group.',
+ tags: [
+ 'User',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the link list of User Groups is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to assign User Groups.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the new User Group does not exist or the User is already in this group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User does not exist.',
+ ],
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject(),
+ ),
+ ),
+)]
+final class UserAssignToUserGroupController extends UserBaseController
+{
+ /**
+ * Assigns the user to a user group.
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function assignUserToUserGroup(int $userId, Request $request): Values\UserGroupRefList
+ {
+ $user = $this->userService->loadUser($userId);
+
+ try {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($request->query->get('group'))
+ );
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ try {
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ try {
+ $this->userService->assignUserToUserGroup($user, $userGroup);
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ $userGroups = $this->userService->loadUserGroupsOfUser($user);
+ $restUserGroups = [];
+ foreach ($userGroups as $userGroup) {
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ $restUserGroups[] = new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ );
+ }
+
+ return new Values\UserGroupRefList(
+ $restUserGroups,
+ $this->router->generate(
+ 'ibexa.rest.load_user_groups_of_user',
+ ['userId' => $userId]
+ ),
+ $userId
+ );
+ }
+
+ /**
+ * Loads a list of users assigned to role.
+ *
+ * @param mixed $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestUser[]
+ */
+ public function loadUsersAssignedToRole($roleId): array
+ {
+ $role = $this->roleService->loadRole($roleId);
+ $roleAssignments = $this->roleService->getRoleAssignments($role);
+
+ $restUsers = [];
+
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment instanceof UserRoleAssignment) {
+ $restUsers[] = $this->buildRestUserObject($roleAssignment->getUser());
+ }
+ }
+
+ return $restUsers;
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserBaseController.php b/src/lib/Server/Controller/User/UserBaseController.php
new file mode 100644
index 000000000..0b9395522
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserBaseController.php
@@ -0,0 +1,133 @@
+userService = $userService;
+ $this->roleService = $roleService;
+ $this->contentService = $contentService;
+ $this->contentTypeService = $contentTypeService;
+ $this->locationService = $locationService;
+ $this->sectionService = $sectionService;
+ $this->repository = $repository;
+ $this->permissionResolver = $permissionResolver;
+ }
+
+ /**
+ * Loads users.
+ */
+ public function loadUsers(Request $request): RestValue
+ {
+ $restUsers = [];
+
+ try {
+ if ($request->query->has('roleId')) {
+ $restUsers = $this->loadUsersAssignedToRole(
+ $this->requestParser->parseHref($request->query->get('roleId'), 'roleId')
+ );
+ } elseif ($request->query->has('remoteId')) {
+ $restUsers = [
+ $this->buildRestUserObject(
+ $this->userService->loadUser(
+ $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'))->id,
+ Language::ALL
+ )
+ ),
+ ];
+ } elseif ($request->query->has('login')) {
+ $restUsers = [
+ $this->buildRestUserObject(
+ $this->userService->loadUserByLogin($request->query->get('login'), Language::ALL)
+ ),
+ ];
+ } elseif ($request->query->has('email')) {
+ foreach ($this->userService->loadUsersByEmail($request->query->get('email'), Language::ALL) as $user) {
+ $restUsers[] = $this->buildRestUserObject($user);
+ }
+ }
+ } catch (ApiExceptions\UnauthorizedException $e) {
+ $restUsers = [];
+ }
+
+ if (empty($restUsers)) {
+ throw new NotFoundException('Could not find Users with the given filter');
+ }
+
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.userlist') {
+ return new Values\UserList($restUsers, $request->getPathInfo());
+ }
+
+ return new Values\UserRefList($restUsers, $request->getPathInfo());
+ }
+
+ protected function buildRestUserObject(RepositoryUser $user): Values\RestUser
+ {
+ return new Values\RestUser(
+ $user,
+ $this->contentTypeService->loadContentType($user->contentInfo->contentTypeId),
+ $user->contentInfo,
+ $this->locationService->loadLocation($user->contentInfo->mainLocationId),
+ $this->contentService->loadRelations($user->getVersionInfo())
+ );
+ }
+
+ /**
+ * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
+ */
+ protected function extractLocationIdFromPath(string $path): int
+ {
+ $pathParts = explode('/', $path);
+
+ return (int)array_pop($pathParts);
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserCreateController.php b/src/lib/Server/Controller/User/UserCreateController.php
new file mode 100644
index 000000000..a79188f4a
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserCreateController.php
@@ -0,0 +1,153 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new User in the given Group.',
+ tags: [
+ 'User Group',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new User is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The UserCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UserCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/users/POST/UserCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.User+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/User',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.xml.example',
+ ],
+ 'application/vnd.ibexa.api.User+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this User.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - a User with the same login already exists.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the Group with the given ID does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserCreateController extends UserBaseController
+{
+ /**
+ * Create a new user group in the given group.
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function createUser(string $groupPath, Request $request): Values\CreatedUser
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+ $userGroup = $this->userService->loadUserGroup($userGroupLocation->contentId);
+
+ $userCreateStruct = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ );
+
+ try {
+ $createdUser = $this->userService->createUser($userCreateStruct, [$userGroup]);
+ } catch (ApiExceptions\InvalidArgumentException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage());
+ }
+
+ $createdContentInfo = $createdUser->getVersionInfo()->getContentInfo();
+ $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
+
+ return new Values\CreatedUser(
+ [
+ 'user' => new Values\RestUser(
+ $createdUser,
+ $contentType,
+ $createdContentInfo,
+ $createdLocation,
+ $this->contentService->loadRelations($createdUser->getVersionInfo())
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserDeleteController.php b/src/lib/Server/Controller/User/UserDeleteController.php
new file mode 100644
index 000000000..5e65ecd90
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserDeleteController.php
@@ -0,0 +1,71 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No Content.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this User.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the user is the same as the authenticated User.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserDeleteController extends UserBaseController
+{
+ /**
+ * Given user is deleted.
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function deleteUser(int $userId): Values\NoContent
+ {
+ $user = $this->userService->loadUser($userId);
+
+ if ($user->id == $this->permissionResolver->getCurrentUserReference()->getUserId()) {
+ throw new Exceptions\ForbiddenException('Cannot delete the currently authenticated User');
+ }
+
+ $this->userService->deleteUser($user);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserDraftListController.php b/src/lib/Server/Controller/User/UserDraftListController.php
new file mode 100644
index 000000000..e48408eae
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserDraftListController.php
@@ -0,0 +1,79 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - List the draft versions',
+ 'content' => [
+ 'application/vnd.ibexa.api.VersionList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionList',
+ ],
+ ],
+ 'application/vnd.ibexa.api.VersionList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/VersionListWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the current user is not authorized to list the drafts of the given user.',
+ ],
+ ],
+ ),
+)]
+final class UserDraftListController extends UserBaseController
+{
+ /**
+ * Loads drafts assigned to user.
+ */
+ public function loadUserDrafts(int $userId, Request $request): Values\VersionList
+ {
+ $contentDrafts = $this->contentService->loadContentDrafts(
+ $this->userService->loadUser($userId)
+ );
+
+ return new Values\VersionList($contentDrafts, $request->getPathInfo());
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupCreateController.php b/src/lib/Server/Controller/User/UserGroupCreateController.php
new file mode 100644
index 000000000..d77c76815
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupCreateController.php
@@ -0,0 +1,216 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Creates a top level User Group under the root. To create a child group under a parent group use \'/user/groups/{path}/subgroups\'.',
+ tags: [
+ 'User Group',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new User Group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The UserGroupCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UserGroupCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'description' => 'Created - the User Group has been created',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this User Group.',
+ ],
+ ],
+ ),
+)]
+#[Post(
+ uriTemplate: '/user/groups/{path}/subgroups',
+ name: 'Create User Group',
+ extraProperties: [OpenApiFactory::OVERRIDE_OPENAPI_RESPONSES => false],
+ openapi: new Model\Operation(
+ summary: 'Creates a new User Group under the given parent. To create a top level group use \'/user/groups/subgroups\'.',
+ tags: [
+ 'User Group',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new User Group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The UserGroupCreate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UserGroupCreate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupCreate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupCreate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupCreateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroupCreate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_CREATED => [
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to create this User Group.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupCreateController extends UserBaseController
+{
+ /**
+ * Create a new user group under the given parent
+ * To create a top level group use /user/groups/1/5/subgroups.
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function createUserGroup(string $groupPath, Request $request): Values\CreatedUserGroup
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $createdUserGroup = $this->userService->createUserGroup(
+ $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent()
+ )
+ ),
+ $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ )
+ );
+
+ $createdContentInfo = $createdUserGroup->getVersionInfo()->getContentInfo();
+ $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
+
+ return new Values\CreatedUserGroup(
+ [
+ 'userGroup' => new Values\RestUserGroup(
+ $createdUserGroup,
+ $contentType,
+ $createdContentInfo,
+ $createdLocation,
+ $this->contentService->loadRelations($createdUserGroup->getVersionInfo())
+ ),
+ ]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupDeleteController.php b/src/lib/Server/Controller/User/UserGroupDeleteController.php
new file mode 100644
index 000000000..a0aea3ab6
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupDeleteController.php
@@ -0,0 +1,76 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_NO_CONTENT => [
+ 'description' => 'No content - the given User Group is deleted.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to delete this content type.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the User Group is not empty.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupDeleteController extends UserBaseController
+{
+ /**
+ * Given user group is deleted.
+ *
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function deleteUserGroup(string $groupPath): Values\NoContent
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ // Load one user to see if user group is empty or not
+ $users = $this->userService->loadUsersOfUserGroup($userGroup, 0, 1);
+ if (!empty($users)) {
+ throw new Exceptions\ForbiddenException('Cannot delete non-empty User Groups');
+ }
+
+ $this->userService->deleteUserGroup($userGroup);
+
+ return new Values\NoContent();
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupListController.php b/src/lib/Server/Controller/User/UserGroupListController.php
new file mode 100644
index 000000000..e9de7341e
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupListController.php
@@ -0,0 +1,164 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroupList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.json.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read User Groups.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupListController extends UserBaseController
+{
+ /**
+ * Loads user groups.
+ */
+ public function loadUserGroups(Request $request): RestValue
+ {
+ $restUserGroups = [];
+ if ($request->query->has('id')) {
+ $userGroup = $this->userService->loadUserGroup($request->query->get('id'), Language::ALL);
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $userGroupMainLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ $restUserGroups = [
+ new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupMainLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ ),
+ ];
+ } elseif ($request->query->has('roleId')) {
+ $restUserGroups = $this->loadUserGroupsAssignedToRole($request->query->get('roleId'));
+ } elseif ($request->query->has('remoteId')) {
+ $restUserGroups = [
+ $this->loadUserGroupByRemoteId($request),
+ ];
+ }
+
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.usergrouplist') {
+ return new Values\UserGroupList($restUserGroups, $request->getPathInfo());
+ }
+
+ return new Values\UserGroupRefList($restUserGroups, $request->getPathInfo());
+ }
+
+ /**
+ * Loads a user group by its remote ID.
+ */
+ public function loadUserGroupByRemoteId(Request $request): Values\RestUserGroup
+ {
+ $contentInfo = $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'));
+ $userGroup = $this->userService->loadUserGroup($contentInfo->id, Language::ALL);
+ $userGroupLocation = $this->locationService->loadLocation($contentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($contentInfo->contentTypeId);
+
+ return new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $contentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ );
+ }
+
+ /**
+ * Loads a list of user groups assigned to role.
+ *
+ * @param mixed $roleId
+ *
+ * @return \Ibexa\Rest\Server\Values\RestUserGroup[]
+ */
+ public function loadUserGroupsAssignedToRole($roleId): array
+ {
+ $role = $this->roleService->loadRole($roleId);
+ $roleAssignments = $this->roleService->getRoleAssignments($role);
+
+ $restUserGroups = [];
+
+ foreach ($roleAssignments as $roleAssignment) {
+ if ($roleAssignment instanceof UserGroupRoleAssignment) {
+ $userGroup = $roleAssignment->getUserGroup();
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ $restUserGroups[] = new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ );
+ }
+ }
+
+ return $restUserGroups;
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupLoadByPathController.php b/src/lib/Server/Controller/User/UserGroupLoadByPathController.php
new file mode 100644
index 000000000..678dc3d5b
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupLoadByPathController.php
@@ -0,0 +1,117 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - loads User Groups.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read User Groups.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User Group does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupLoadByPathController extends UserBaseController
+{
+ /**
+ * Loads a user group for the given path.
+ */
+ public function loadUserGroup(string $groupPath): RestValue
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ if (trim($userGroupLocation->pathString, '/') !== $groupPath) {
+ throw new NotFoundException(
+ "Could not find a Location with path string $groupPath"
+ );
+ }
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId,
+ Language::ALL
+ );
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ return new Values\CachedValue(
+ new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ ),
+ ['locationId' => $userGroupLocation->id]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupMoveController.php b/src/lib/Server/Controller/User/UserGroupMoveController.php
new file mode 100644
index 000000000..670040f8d
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupMoveController.php
@@ -0,0 +1,111 @@
+locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ $locationPath = $this->requestParser->parseHref(
+ $request->headers->get('Destination'),
+ 'groupPath'
+ );
+
+ try {
+ $destinationGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($locationPath)
+ );
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ try {
+ $destinationGroup = $this->userService->loadUserGroup($destinationGroupLocation->contentId);
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ $this->userService->moveUserGroup($userGroup, $destinationGroup);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_user_group',
+ [
+ 'groupPath' => trim($destinationGroupLocation->pathString, '/') . '/' . $userGroupLocation->id,
+ ]
+ )
+ );
+ }
+
+ /**
+ * @throws \Ibexa\Contracts\Rest\Exceptions\ForbiddenException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function moveGroup(string $groupPath, Request $request): Values\ResourceCreated
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId,
+ );
+
+ try {
+ /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $destinationLocation */
+ $destinationLocation = $this->inputDispatcher->parse(
+ new Message(
+ ['Content-Type' => $request->headers->get('Content-Type')],
+ $request->getContent(),
+ ),
+ );
+ } catch (ApiExceptions\NotFoundException $e) {
+ throw new ForbiddenException(/** @Ignore */ $e->getMessage(), 1, $e);
+ }
+
+ $destinationGroup = $this->userService->loadUserGroup(
+ $destinationLocation->getContent()->getId(),
+ );
+
+ $this->userService->moveUserGroup($userGroup, $destinationGroup);
+
+ return new Values\ResourceCreated(
+ $this->router->generate(
+ 'ibexa.rest.load_user_group',
+ [
+ 'groupPath' => trim($destinationLocation->pathString, '/')
+ . '/'
+ . $userGroupLocation->getId(),
+ ],
+ )
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupOfRootLoadController.php b/src/lib/Server/Controller/User/UserGroupOfRootLoadController.php
new file mode 100644
index 000000000..907cb5586
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupOfRootLoadController.php
@@ -0,0 +1,45 @@
+ [
+ 'description' => 'Moved permanently.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupOfRootLoadController extends UserBaseController
+{
+ /**
+ * Redirects to the root user group.
+ */
+ public function loadRootUserGroup(): Values\PermanentRedirect
+ {
+ //@todo Replace hardcoded value with one loaded from settings
+ return new Values\PermanentRedirect(
+ $this->router->generate('ibexa.rest.load_user_group', ['groupPath' => '/1/5'])
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupUpdateController.php b/src/lib/Server/Controller/User/UserGroupUpdateController.php
new file mode 100644
index 000000000..a6147b50d
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupUpdateController.php
@@ -0,0 +1,155 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a User Group. PATCH or POST with header X-HTTP-Method-Override PATCH.',
+ tags: [
+ 'User Group',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the new User Group is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The UserGroupUpdate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'Performs the PATCH only if the specified ETag is the current one. Otherwise a 412 is returned.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UserGroupUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/PATCH/UserGroupUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - updated User Group.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroup+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroup',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroup+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/path/subgroups/POST/UserGroup.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update the User Group.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - if the current ETag does not match with the one provided in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupUpdateController extends UserBaseController
+{
+ public function updateUserGroup(string $groupPath, Request $request): Values\RestUserGroup
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ // @todo Needs refactoring! Temporary solution so parser has access to URL
+ 'Url' => $request->getPathInfo(),
+ ],
+ $request->getContent()
+ )
+ );
+
+ if ($updateStruct->sectionId !== null) {
+ $section = $this->sectionService->loadSection($updateStruct->sectionId);
+ $this->sectionService->assignSection(
+ $userGroup->getVersionInfo()->getContentInfo(),
+ $section
+ );
+ }
+
+ $updatedGroup = $this->userService->updateUserGroup($userGroup, $updateStruct->userGroupUpdateStruct);
+ $contentType = $this->contentTypeService->loadContentType(
+ $updatedGroup->getVersionInfo()->getContentInfo()->contentTypeId
+ );
+
+ return new Values\RestUserGroup(
+ $updatedGroup,
+ $contentType,
+ $updatedGroup->getVersionInfo()->getContentInfo(),
+ $userGroupLocation,
+ $this->contentService->loadRelations($updatedGroup->getVersionInfo())
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupUsersListController.php b/src/lib/Server/Controller/User/UserGroupUsersListController.php
new file mode 100644
index 000000000..0c50762b0
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupUsersListController.php
@@ -0,0 +1,135 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - the Users of the Group with the given ID.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserList',
+ ],
+ ],
+ 'application/vnd.ibexa.api.UserList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserList',
+ ],
+ ],
+ 'application/vnd.ibexa.api.UserRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/GET/UserRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/id/users/GET/UserRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read User Groups.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User Group does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupUsersListController extends UserBaseController
+{
+ /**
+ * Loads the users of the group with the given path.
+ */
+ public function loadUsersFromGroup(string $groupPath, Request $request): RestValue
+ {
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
+
+ $users = $this->userService->loadUsersOfUserGroup(
+ $userGroup,
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : 25,
+ Language::ALL
+ );
+
+ $restUsers = [];
+ foreach ($users as $user) {
+ $userContentInfo = $user->getVersionInfo()->getContentInfo();
+ $userLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
+
+ $restUsers[] = new Values\RestUser(
+ $user,
+ $contentType,
+ $userContentInfo,
+ $userLocation,
+ $this->contentService->loadRelations($user->getVersionInfo())
+ );
+ }
+
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.userlist') {
+ return new Values\CachedValue(
+ new Values\UserList($restUsers, $request->getPathInfo()),
+ ['locationId' => $userGroupLocation->id]
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\UserRefList($restUsers, $request->getPathInfo()),
+ ['locationId' => $userGroupLocation->id]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserGroupsOfUserListController.php b/src/lib/Server/Controller/User/UserGroupsOfUserListController.php
new file mode 100644
index 000000000..ef9a8e525
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserGroupsOfUserListController.php
@@ -0,0 +1,112 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read User Groups.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the user does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserGroupsOfUserListController extends UserBaseController
+{
+ /**
+ * Returns a list of user groups the user belongs to.
+ * The returned list includes the resources for unassigning
+ * a user group if the user is in multiple groups.
+ */
+ public function loadUserGroupsOfUser(int $userId, Request $request): RestValue
+ {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
+
+ $user = $this->userService->loadUser($userId);
+ $userGroups = $this->userService->loadUserGroupsOfUser(
+ $user,
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : 25,
+ Language::ALL
+ );
+
+ $restUserGroups = [];
+ foreach ($userGroups as $userGroup) {
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ $restUserGroups[] = new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\UserGroupRefList($restUserGroups, $request->getPathInfo(), $userId),
+ ['locationId' => $user->contentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserListController.php b/src/lib/Server/Controller/User/UserListController.php
new file mode 100644
index 000000000..348cd40bb
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserListController.php
@@ -0,0 +1,71 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - Loads Users either for a given remote ID or Role.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example',
+ ],
+ 'application/vnd.ibexa.api.UserRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/GET/UserRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserRefListWrapper',
+ ],
+ ],
+ ],
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'If there are no visibile Users matching the filter.',
+ ],
+ ],
+ ),
+)]
+final class UserListController extends UserBaseController
+{
+}
diff --git a/src/lib/Server/Controller/User/UserLoadByIdController.php b/src/lib/Server/Controller/User/UserLoadByIdController.php
new file mode 100644
index 000000000..a63c7430e
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserLoadByIdController.php
@@ -0,0 +1,120 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-None-Match',
+ in: 'header',
+ required: true,
+ description: 'ETag',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - the User with the given ID.',
+ 'content' => [
+ 'application/vnd.ibexa.api.User+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example',
+ ],
+ 'application/vnd.ibexa.api.User+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Users.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserLoadByIdController extends UserBaseController
+{
+ public function loadUser(int $userId): RestValue
+ {
+ $user = $this->userService->loadUser($userId, Language::ALL);
+
+ $userContentInfo = $user->getVersionInfo()->getContentInfo();
+ $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
+
+ try {
+ $userMainLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
+ $relations = $this->contentService->loadRelations($user->getVersionInfo());
+ } catch (UnauthorizedException $e) {
+ // TODO: Hack for special case to allow current logged in user to load him/here self (but not relations)
+ if ($user->id == $this->permissionResolver->getCurrentUserReference()->getUserId()) {
+ $userMainLocation = $this->repository->sudo(
+ function () use ($userContentInfo) {
+ return $this->locationService->loadLocation($userContentInfo->mainLocationId);
+ }
+ );
+ // user may not have permissions to read related content, for security reasons do not use sudo().
+ $relations = [];
+ } else {
+ throw $e;
+ }
+ }
+
+ return new Values\CachedValue(
+ new Values\RestUser(
+ $user,
+ $contentType,
+ $userContentInfo,
+ $userMainLocation,
+ $relations
+ ),
+ ['locationId' => $userContentInfo->mainLocationId]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserRedirectToCurrentUserController.php b/src/lib/Server/Controller/User/UserRedirectToCurrentUserController.php
new file mode 100644
index 000000000..12fd43d1c
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserRedirectToCurrentUserController.php
@@ -0,0 +1,78 @@
+ 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - the User with the given ID.',
+ 'content' => [
+ 'application/vnd.ibexa.api.User+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.xml.example',
+ ],
+ 'application/vnd.ibexa.api.User+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/GET/User.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read Users. For example, Anonymous user can\'t load oneself.',
+ ],
+ ],
+ ),
+)]
+final class UserRedirectToCurrentUserController extends UserBaseController
+{
+ /**
+ * @see \Symfony\Component\Security\Http\Controller\UserValueResolver
+ */
+ public function redirectToCurrentUser(?UserInterface $user): Values\TemporaryRedirect
+ {
+ if ($user === null) {
+ throw new UnauthorizedHttpException('', 'Not logged in.');
+ }
+
+ $userReference = $this->permissionResolver->getCurrentUserReference();
+
+ return new Values\TemporaryRedirect(
+ $this->router->generate('ibexa.rest.load_user', ['userId' => $userReference->getUserId()])
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserSubGroupListController.php b/src/lib/Server/Controller/User/UserSubGroupListController.php
new file mode 100644
index 000000000..29d4de141
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserSubGroupListController.php
@@ -0,0 +1,137 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'path',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - list of the subgroups.',
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroupList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/groups/GET/UserGroupList.json.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user has no permission to read User Groups.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User Group does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserSubGroupListController extends UserBaseController
+{
+ /**
+ * Returns a list of the sub groups.
+ */
+ public function loadSubUserGroups(string $groupPath, Request $request): RestValue
+ {
+ $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
+ $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
+
+ $userGroupLocation = $this->locationService->loadLocation(
+ $this->extractLocationIdFromPath($groupPath)
+ );
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ $subGroups = $this->userService->loadSubUserGroups(
+ $userGroup,
+ $offset >= 0 ? $offset : 0,
+ $limit >= 0 ? $limit : 25,
+ Language::ALL
+ );
+
+ $restUserGroups = [];
+ foreach ($subGroups as $subGroup) {
+ $subGroupContentInfo = $subGroup->getVersionInfo()->getContentInfo();
+ $subGroupLocation = $this->locationService->loadLocation($subGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($subGroupContentInfo->contentTypeId);
+
+ $restUserGroups[] = new Values\RestUserGroup(
+ $subGroup,
+ $contentType,
+ $subGroupContentInfo,
+ $subGroupLocation,
+ $this->contentService->loadRelations($subGroup->getVersionInfo())
+ );
+ }
+
+ if ($this->getMediaType($request) === 'application/vnd.ibexa.api.usergrouplist') {
+ return new Values\CachedValue(
+ new Values\UserGroupList($restUserGroups, $request->getPathInfo()),
+ ['locationId' => $userGroupLocation->id]
+ );
+ }
+
+ return new Values\CachedValue(
+ new Values\UserGroupRefList($restUserGroups, $request->getPathInfo()),
+ ['locationId' => $userGroupLocation->id]
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserUnassignFromUserGroupController.php b/src/lib/Server/Controller/User/UserUnassignFromUserGroupController.php
new file mode 100644
index 000000000..8802ac8cb
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserUnassignFromUserGroupController.php
@@ -0,0 +1,132 @@
+ 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'groupId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.UserGroupRefList+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefList',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/POST/UserGroupRefList.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserGroupRefList+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserGroupRefListWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/groups/group_id/UserGroupRefList.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to unassign User Groups.',
+ ],
+ Response::HTTP_FORBIDDEN => [
+ 'description' => 'Error - the User is not in the given group.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User does not exist.',
+ ],
+ ],
+ ),
+)]
+final class UserUnassignFromUserGroupController extends UserBaseController
+{
+ /**
+ * Unassigns the user from a user group.
+ *
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
+ * @throws \Ibexa\Contracts\Rest\Exceptions\NotFoundException
+ * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException
+ */
+ public function unassignUserFromUserGroup(int $userId, string $groupPath): Values\UserGroupRefList
+ {
+ $user = $this->userService->loadUser($userId);
+ $userGroupLocation = $this->locationService->loadLocation((int)trim($groupPath, '/'));
+
+ $userGroup = $this->userService->loadUserGroup(
+ $userGroupLocation->contentId
+ );
+
+ try {
+ $this->userService->unAssignUserFromUserGroup($user, $userGroup);
+ } catch (ApiExceptions\InvalidArgumentException $e) {
+ // User is not in the group
+ throw new Exceptions\ForbiddenException($e->getMessage());
+ }
+
+ $userGroups = $this->userService->loadUserGroupsOfUser($user);
+ $restUserGroups = [];
+ foreach ($userGroups as $userGroup) {
+ $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
+ $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
+
+ $restUserGroups[] = new Values\RestUserGroup(
+ $userGroup,
+ $contentType,
+ $userGroupContentInfo,
+ $userGroupLocation,
+ $this->contentService->loadRelations($userGroup->getVersionInfo())
+ );
+ }
+
+ return new Values\UserGroupRefList(
+ $restUserGroups,
+ $this->router->generate(
+ 'ibexa.rest.load_user_groups_of_user',
+ ['userId' => $userId]
+ ),
+ $userId
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserUpdateController.php b/src/lib/Server/Controller/User/UserUpdateController.php
new file mode 100644
index 000000000..be4dc4609
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserUpdateController.php
@@ -0,0 +1,152 @@
+ false],
+ openapi: new Model\Operation(
+ summary: 'Updates a User.',
+ tags: [
+ 'User',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'If set, the updated User is returned in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The UserUpdate schema encoded in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'If-Match',
+ in: 'header',
+ required: true,
+ description: 'Performs a PATCH only if the specified ETag is the current one.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'userId',
+ in: 'path',
+ required: true,
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.UserUpdate+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserUpdate',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.xml.example',
+ ],
+ 'application/vnd.ibexa.api.UserUpdate+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserUpdateWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/UserUpdate.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'description' => 'OK - User updated.',
+ 'content' => [
+ 'application/vnd.ibexa.api.User+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/User',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.xml.example',
+ ],
+ 'application/vnd.ibexa.api.User+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/UserWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/users/user_id/PATCH/User.json.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ Response::HTTP_UNAUTHORIZED => [
+ 'description' => 'Error - the user is not authorized to update the User.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - the User does not exist.',
+ ],
+ Response::HTTP_PRECONDITION_FAILED => [
+ 'description' => 'Error - the current ETag does not match with the provided one in the If-Match header.',
+ ],
+ ],
+ ),
+)]
+final class UserUpdateController extends UserBaseController
+{
+ public function updateUser(int $userId, Request $request): Values\RestUser
+ {
+ $user = $this->userService->loadUser($userId);
+
+ $updateStruct = $this->inputDispatcher->parse(
+ new Message(
+ [
+ 'Content-Type' => $request->headers->get('Content-Type'),
+ // @todo Needs refactoring! Temporary solution so parser has access to URL
+ 'Url' => $request->getPathInfo(),
+ ],
+ $request->getContent()
+ )
+ );
+
+ if ($updateStruct->sectionId !== null) {
+ $section = $this->sectionService->loadSection($updateStruct->sectionId);
+ $this->sectionService->assignSection(
+ $user->getVersionInfo()->getContentInfo(),
+ $section
+ );
+ }
+
+ $updatedUser = $this->userService->updateUser($user, $updateStruct->userUpdateStruct);
+ $updatedContentInfo = $updatedUser->getVersionInfo()->getContentInfo();
+ $mainLocation = $this->locationService->loadLocation($updatedContentInfo->mainLocationId);
+ $contentType = $this->contentTypeService->loadContentType($updatedContentInfo->contentTypeId);
+
+ return new Values\RestUser(
+ $updatedUser,
+ $contentType,
+ $updatedContentInfo,
+ $mainLocation,
+ $this->contentService->loadRelations($updatedUser->getVersionInfo())
+ );
+ }
+}
diff --git a/src/lib/Server/Controller/User/UserVerifyController.php b/src/lib/Server/Controller/User/UserVerifyController.php
new file mode 100644
index 000000000..fb8082f82
--- /dev/null
+++ b/src/lib/Server/Controller/User/UserVerifyController.php
@@ -0,0 +1,47 @@
+ [
+ 'description' => 'OK - verifies if there are Users matching the given filter.',
+ ],
+ Response::HTTP_NOT_FOUND => [
+ 'description' => 'Error - there are no visibile Users matching the filter.',
+ ],
+ ],
+ ),
+)]
+final class UserVerifyController extends UserBaseController
+{
+ public function verifyUsers(Request $request): Values\OK
+ {
+ // We let the NotFoundException loadUsers throws if there are no results pass.
+ $this->loadUsers($request)->users;
+
+ return new Values\OK();
+ }
+}
diff --git a/src/lib/Server/Controller/Views.php b/src/lib/Server/Controller/Views.php
index 1e29c3643..9f1d67954 100644
--- a/src/lib/Server/Controller/Views.php
+++ b/src/lib/Server/Controller/Views.php
@@ -7,6 +7,10 @@
namespace Ibexa\Rest\Server\Controller;
+use ApiPlatform\Metadata\Get;
+use ApiPlatform\Metadata\Post;
+use ApiPlatform\OpenApi\Factory\OpenApiFactory;
+use ApiPlatform\OpenApi\Model;
use Ibexa\Contracts\Core\Repository\Exceptions\NotImplementedException;
use Ibexa\Contracts\Core\Repository\SearchService;
use Ibexa\Contracts\Core\Repository\Values\Content\Language;
@@ -15,7 +19,72 @@
use Ibexa\Rest\Server\Controller;
use Ibexa\Rest\Server\Values;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+#[Post(
+ uriTemplate: '/views',
+ name: 'Search content',
+ extraProperties: [OpenApiFactory::OVERRIDE_OPENAPI_RESPONSES => false],
+ openapi: new Model\Operation(
+ summary: 'Executes a query and returns a View including the results.
+View input reflects the criteria model of the public PHP API.
+Refer to [Search Criteria Reference](/en/latest/search/criteria_reference/search_criteria_reference/)',
+ tags: [
+ 'Views',
+ ],
+ parameters: [
+ new Model\Parameter(
+ name: 'Accept',
+ in: 'header',
+ required: true,
+ description: 'The view in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ new Model\Parameter(
+ name: 'Content-Type',
+ in: 'header',
+ required: true,
+ description: 'The view input in XML or JSON format.',
+ schema: [
+ 'type' => 'string',
+ ],
+ ),
+ ],
+ requestBody: new Model\RequestBody(
+ content: new \ArrayObject([
+ 'application/vnd.ibexa.api.ViewInput+xml' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ViewInput',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/views/POST/ViewInput.xml.example',
+ ],
+ 'application/vnd.ibexa.api.ViewInput+json' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/ViewInputWrapper',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/views/POST/ViewInput.json.example',
+ ],
+ ]),
+ ),
+ responses: [
+ Response::HTTP_OK => [
+ 'content' => [
+ 'application/vnd.ibexa.api.View+xml; version=1.1' => [
+ 'schema' => [
+ '$ref' => '#/components/schemas/View',
+ ],
+ 'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/views/POST/View.xml.v11.example',
+ ],
+ ],
+ ],
+ Response::HTTP_BAD_REQUEST => [
+ 'description' => 'Error - the input does not match the input schema definition.',
+ ],
+ ],
+ ),
+)]
/**
* Controller for Repository Views (Search, mostly).
*/