October: Deferred binding update does not work as expected

Created on 1 Nov 2020  路  8Comments  路  Source: octobercms/october

  • OctoberCMS Build: 469
  • PHP Version: 7.3.6
  • Database Engine: 10.3.16-MariaDB

Description:

I have a simple PARENT "hasMany" CHILDREN relation.
In the form of the parent i use a RelationController to create new children for the parent.
As the parent did not exist at first, the relation uses deferred binding.

If i create a new child within a new and unsafed parent, everything works as expected:

  • The child is created with parent_id=null
  • An entry is made in the deferred_bindings table
  • After saving the parent, the parent_id gets updated correctly

image
image

If i EDIT this parent, add another children and click CANCEL, i would expect the new child is also deferred and not actually assigned to the parent. But it is, even though there is a entry in the deferred bindings table too. That is strange.

image
image

Steps To Reproduce:

Install plugin from https://github.com/cx0onl/oc-deferredupdatebug-plugin to reproduce.

1.) Create new Parent, add Children, save
2.) Edit parent, add Children, cancel

Bug help wanted

Most helpful comment

@LukeTowers I've seen this behaviour on the test plugin, and I tend to agree with @cx0onl's assessment of what's going on here - deferred binding should apply across the board if it's enabled, not just on creation. It's never really bothered me before, but this would meet the expectations of most users in that nothing of their data entry is applied until the "Save" action is hit, even if the data modified is for a related model.

All 8 comments

Deferred binding is meant for parent records that don't exist. If the parent record does exist, why wouldn't it attach directly?

https://octobercms.com/docs/database/relations#deferred-binding

Deferred bindings allows you to postpone model relationships binding until the master record commits the changes.
...
You can defer any number of slave models against a master model using a session key. When the master record is saved along with the session key, the relationships to slave records are updated automatically for you. Deferred bindings are supported in the back-end Form behavior automatically, but you may want to use this feature in other places.`

If I understood the docu correctly, this is the expected behavior. The relations are updated only when the parent gets saved.

It is also confusing if the user clicks on Cancel but the parent is changed anyway. (Adding children is a change of the parent)

If you are right, why is an entry created in the deferred_bindings table when the child is appended directly?

I did some more research and I think that deferred binding in the RelationController was not implemented as it should be.

I have explicitly set the option deferredBinding: true in relation_config.yaml.

According to https://octobercms.com/docs/database/relations#defer-binding I would expect that any addition or deletion of a child is only committed when the parent is saved.

Furthermore, I would expect that canceling the edit of the parent would also abort all deferred bindings and delete the orphans.

Are there any reasons why this is not implemented in that way? Or is there something wrong with my code which prevents deferred bindings to work?

@LukeTowers I've seen this behaviour on the test plugin, and I tend to agree with @cx0onl's assessment of what's going on here - deferred binding should apply across the board if it's enabled, not just on creation. It's never really bothered me before, but this would meet the expectations of most users in that nothing of their data entry is applied until the "Save" action is hit, even if the data modified is for a related model.

@bennothommo I would agree with that too, especially if deferredBinding has been explicitly enabled

I think i found the lines causing this bug:

https://github.com/octobercms/october/blob/fffa6db8d8b9dddd6b8fca79ffed26753029d59f/modules/backend/behaviors/RelationController.php#L1098-L1108

While creating the Child model, the parent_id is manually inserted in the foreign key column. This completely bypasses the mechanism of deferred binding. When i remove these lines, it works as expected.

@daftspunk added this as a fix for #1541 five years ago.

BTW: Till yesterday i used "delete" as action to remove childs. But "delete" is not deferred at all. "remove" ist the right action to go. The docu was not clear for me in this point. After reading the sourcecode i understood. So removing is now also working as desired.

@cx0onl the relation handling of october is a bit confusing from end user's side. Even if this will be fixed, the update of an existing child model leads to the same behavior (in update context of parent). User expects: while the parent is not saved, the modification of child is not saved too. But the child is saved in this case becasue it has been attached to parent before.

This issue will be closed and archived in 3 days, as there has been no activity in the last 60 days.
If this issue is still relevant or you would like to see it actioned, please respond and we will re-open this issue.
If this issue is critical to your business, consider joining the Premium Support Program where a Service Level Agreement is offered.

Was this page helpful?
0 / 5 - 0 ratings