Mysterious behaviour with PUT route

Issue #32 resolved
Alexander Grein created an issue

Maybe it’s a (undocumented) new feature, but I have a mysterious behaviour since a while in a project where using nnrestapi.

I have an entrypoint method with this annotations:

/**
* Add debaters to competition
*
* @Api\Route("PUT competition/{competition}/debaters")
* @Api\Access("config[competitionApi]")
* @Api\Example("{'debaters':[1,2,3,4]}")
*
* @param Competition $competition
* @return Response
*/
public function addDebaters(Competition $competition): Response
{
    try {
        $dabaterUids = array_map('intval', $this->request->getBody()['debaters']);
        $currentDebaters = $competition->getDebaters();

This method should add new debaters to a competition later in the code. The debaters to add will be send as a json array like so:

{
    "debaters": [
        860,
        867,
        1100
    ]
}

The Competition model has a propery “debaters” with a getter and setter method.

Since a while, maybe it comes with an update of this extension (nnrestapi), the $competition->getDebaters() call already contains the just send debaters, without I ever had added theme before!

But if I create a breakpoint in line 15 of the example, the database doesn’t contain them.

This is really problematic, because this way, all new added debaters will kick off the previous added ones!

The only workaround I found, was to change {competition} to {competitionUid} (and Competiton to int) and take the competition out of it’s repository by doing $competition = $this->competitionRepository->findByUid($competitionUid).

Is there an other way to fix this problem and when this “feature” comes in?

Comments (8)

  1. David Bascom

    Sorry for the late answer.

    Yes – this actually is intended to make easy merging of the JSON-body with an existing Model possible (e.g. for FAL-ObjectStorages like in this example).

    The way it works is:

    • The nnrestapi-ApiController checks, if the Endpoint wants a Model as argument and if an uid was passed in the path / URL or inside the JSON-body ({"uid":1, ...})
    • It then retrieves the Model from the database

    • Before it calls the endpoint and passes the Model as argument, the body of the JSON-Request is merged in the existing Model, but not persisted (this explains, why you see the changes in the Model but not in the database)

    • The merged Model is then passed to the method. It is up to the method to decide, if it will persist it.

    The line that causes the problem in your case is probably in the nnrest-ApiController here:

    // merge data from request with existing model
    $model = \nn\t3::Obj( $existingModel )->merge( $modelData ); 
    

    The options / workarounds you mentioned are perfectly correct and suitable. Another option would be to “clone” the ApiController in to your own extension and remove the line above. This can be done with this setting in TypoScript.

    On the other hand: I can fully understand, that it will cause conflicts in your case and a might cause some irritations for other users. Would it be an option to implement a TypoScript setting to disable the auto-merging? We could have it in the next release.

  2. Alexander Grein reporter

    A typoscript setting to disable this auto-merge would be a good thing, but what about another annotation?
    @Api\AutoMerge("false")
    This way, it would be possible to disable it in a specific case.

  3. Log in to comment