Skip to content

Slice endpoints silently drop value20 (loop caps at 19, table has 20 columns) #52

Description

@anveno

(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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions