(Hinweis: Das Issue hat mir Claude Code erstellt)
Summary
The slice Body schema is built with a loop that stops at value19, but rex_article_slice has 20 value columns and rex_content_service::addSlice() writes any key it is handed. A value20 sent to the API is therefore silently discarded — no 400, no warning, the slice is created with HTTP 201 and the field simply stays empty.
Affects both POST /api/structure/articles/{id}/slices and PUT|PATCH /api/structure/articles/{id}/slices/{slice_id}.
Where
lib/RoutePackage/Structure.php
for ($i = 1; $i <= 19; ++$i) {
$Values['value' . $i] = [
'type' => 'string',
'required' => false,
'default' => null,
];
if ($i <= 10) {
$Medias['media' . $i] = [ /* … */ ];
$Medialists['medialist' . $i] = [ /* … */ ];
$Links['link' . $i] = [ /* … */ ];
$Linklists['linklist' . $i] = [ /* … */ ];
}
}
$Values is then merged into the Body of the slice add route and the slice update route.
The inner $i <= 10 is correct — rex_article_slice really has 10 media/medialist/link/linklist columns each. The outer 19 is the odd one out:
MariaDB> SHOW COLUMNS FROM rex_article_slice LIKE 'value%'; -- 20 rows, value1 … value20
And the core service does not impose any limit (structure/plugins/content/lib/content_service.php):
foreach ($data as $key => $value) {
$sql->setValue($key, $value);
}
So value20 would be written just fine if it survived the body validation.
Why it is silent
RouteCollection::getQuerySet() iterates over the definition, not over the request:
foreach ($definition as $key => $value) {
Keys present in the request but absent from the definition are dropped without an error. From the client's side the request looks completely successful.
Reproduce
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"module_id":<id>,"ctype_id":1,"clang_id":1,"value19":"a","value20":"b"}' \
"https://example.org/api/structure/articles/<article_id>/slices"
→ 201 {"message":"ArticleSlice created","slice_id":"…"}
SELECT value19, value20 FROM rex_article_slice WHERE id = <slice_id>;
-- value19 = 'a', value20 = NULL
Impact
Modules that use value20 cannot be transported through the API at all, and nothing indicates it. We commonly park a "style" or "options" tab in the last value slot, precisely because it is the one furthest away from the content fields. In our project every module keeps its style tab in value20, so every slice created through the API comes out with default styling and has to be corrected by hand in the backend.
Suggested fix
-for ($i = 1; $i <= 19; ++$i) {
+for ($i = 1; $i <= 20; ++$i) {
If the cap is intentional for some reason I am not seeing, then it would help a lot if unknown body keys produced a 400 instead of being dropped — silent loss is the worse half of the problem.
Environment
- api addon 1.2
- REDAXO 5.21.1
- PHP 8.4
- MariaDB 10.11
(Hinweis: Das Issue hat mir Claude Code erstellt)
Summary
The slice
Bodyschema is built with a loop that stops atvalue19, butrex_article_slicehas 20valuecolumns andrex_content_service::addSlice()writes any key it is handed. Avalue20sent to the API is therefore silently discarded — no 400, no warning, the slice is created with HTTP 201 and the field simply stays empty.Affects both
POST /api/structure/articles/{id}/slicesandPUT|PATCH /api/structure/articles/{id}/slices/{slice_id}.Where
lib/RoutePackage/Structure.php$Valuesis then merged into theBodyof the slice add route and the slice update route.The inner
$i <= 10is correct —rex_article_slicereally has 10media/medialist/link/linklistcolumns each. The outer19is the odd one out:And the core service does not impose any limit (
structure/plugins/content/lib/content_service.php):So
value20would be written just fine if it survived the body validation.Why it is silent
RouteCollection::getQuerySet()iterates over the definition, not over the request:Keys present in the request but absent from the definition are dropped without an error. From the client's side the request looks completely successful.
Reproduce
→
201 {"message":"ArticleSlice created","slice_id":"…"}Impact
Modules that use
value20cannot be transported through the API at all, and nothing indicates it. We commonly park a "style" or "options" tab in the last value slot, precisely because it is the one furthest away from the content fields. In our project every module keeps its style tab invalue20, so every slice created through the API comes out with default styling and has to be corrected by hand in the backend.Suggested fix
If the cap is intentional for some reason I am not seeing, then it would help a lot if unknown body keys produced a
400instead of being dropped — silent loss is the worse half of the problem.Environment