cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Antonio Gallardo" <agalla...@agssa.net>
Subject Re: [cforms] Repeater Binding Revisited.
Date Tue, 30 Mar 2004 08:15:08 GMT
Hi Marc!


Because seems like you will start soon. I will not miss the oportunity to
get into. So here we go! ;-D
Marc Portier dijo:
> Hi all,
>
> Long due, but here goes...
>
> Over time our RepeaterBinding has been reported as behaving 'odd' and as
> 'not expected', in the best cases some argumentation could bend those
> into 'unobvious'...
> The brave among us probably just patch the beast or make their own
> 'SimpleRepeaterBinding' and go on with their job...
>
> Towards the larger user-base I think we should unify views, clean out
> the code and provide appropriate documentation.
>
> So, here is an attempt to bring the sheep back into the heard, and lay
> down a better foundation for the RepeaterBinding implementation as well
> as its use (and thus its documentation)
>
> As always: remarks, additions and suggestions are welcomed.
> (Upfront: thx for reading through. It's lengthy, but the goal to cover
> all 'expectations' kind of requires that)
>
>
> Thinking and Talking about this
> -------------------------------
> During my preparation of this I kinda developed my own nomenclature that
> helped me sort out things.  Hoping this helps you too:
>
> CForms Binding serves as a declarative way to describe the mapping
> between the backend-model and the cforms form-model.
> An active Binding object will allow both 'load' (filling form-model with
> data) and 'save' (writing form-model to backend-model) operations
>
> The cforms form-model consists of a tree of widgets.
> On the backend side the JXPath support offers a comparable hierarchical
> view on the model.  At each evaluated jxpath expression we find a
> context object which in its turn can serve as a bean under wich more
> jxpath expressions can be evaluated.
>
> When we talk about the RepeaterBinding then it is assumed to work between
> - a selected REPEATERWidget from the form-model which holds a number of
> ROWS of actual WIDGETS, and
> - a CONTEXTBEAN on the backend-model that behaves as a collection of
> ITEMS that have PROPERTIES
>
> The mapping to declare on the various levels is thus something like:
> +--------+              +-----------+
> |repeater|       <----> |contextbean|
> +.-------+              +-.---------+
>   |   +---+                |    +----+
>   ----|row|       <---->   -----|item|
>       +-.-+                     +-.--+
>         | +------+                |  +--------+
>         --|widget|<---->          ---|property|
>           +------+                   +--------+
>
> looking into the <fb:repeater> syntax we see these mappings back in the
> names of the attributes:
>
> @id points to the repeater
> @parent-path points to the matching contextbean
> the repeater's rows each map to one item found at @row-path within the
> contextbean
> the nested child-widgets will map @id of widget to @path of actual
> property.

In the case of nested childs I meet the situation where we often wrote:

<fb:value id="key1" path="key1"/>
<fb:value id="key2" path="key2"/>
...

So the question is:

Can we "save" typing by defining a default value for @path. That way we
can also write:

<fb:value id="key1"/>
<fb:value id="key2"/>

And in this way the machine will fill the @path for me.

> On the 'save'-direction however things are not that self-explaining, and
> depending on one's use case the expected strategy of the
> repeater-binding would be radically different... to be able to cater for
> all those expectations we need to at least know and understand them,
> below is how I've seen that list, grown to 4 over the past months.
>
> The idea is to describe them, immidiately propose a solution and then
> start jamming the code in as soon as we can reach consensus...

Great!

>                            -o0o-
> [case 1]
> DESCRIPTION:
> - the form handling (actions or events) will not reorder the rows
> - no rows will be added or deleted
> - item-properties could be sparsly bound to row-widgets (meaning: not
> all properties are mapped to actual widgets since they're not part of
> the foreseen end-user interaction scheme, of course the ones that were
> not bound should not be cleared on save just because the form-model
> isn't holding a value for them)
>
> In this case we don't really speak of identity of the items, and we
> don't really need it either: the position of each item in the list (it's
> index) serves as an implicit identifier, and since no adding/deleting or
> reordering on the rows can happen we know that the row-indexes will just
> keep in sync.
>
> PROPOSED SYNTAX:
> <fb:repeater id="rep-id" parent-path="."
>                row-path="item">
>    <!-- no fb:identity -->
>    <!--required elements for this case -->
>    <fb:on-bind>...</fb:on-bind>
>    <!--optional elements for this case -->
>    <fb:on-insert>..</fb:on-insert>
>    <fb:on-delete>..</fb:on-delete>
> </fb:repeater>
>
> EXPECTATION DETECTION:
> - no nested <fb:identity> element tells us we don't have an explicit
> identity, and we should just trust the index as a identity correlator.
>
> STRATEGY on 'save':
> - foreach row in repeater
>    - use the nested 'on-bind' binding
>
> A straightforward extension seems to be
> - allow for add/delete of rows (by adding <on-insert> <on-delete>)
> - at the cost of not surviving sparse binding of items.
>
> Then the Strategy becomes:
> - foreach row in repeater with matching index in the items
>    - use the nested 'on-bind' binding
> - for excess rows in the repeater
>    - use on-insert and on-bind
> - for excess items in the context
>    - use on-delete
>
>                            -o0o-
>
>
> [case 2] (aka current SimpleRepeaterBinding)
> DESCRIPTION:
> - no fluff, just stuff
> - the simplicity of 'load' ported over to 'save'
>
> - we can just remove all the items before binding them from the form
>    (thus no expected support for sparse binding)
> - form-model can be changed at will
>
> PROPOSED SYNTAX:
> <fb:repeater id="rep-id" parent-path="."
>               row-path="item"
>               clear-items-on-save="true">
>    <!-- no fb:identity -->
>    <!--required elements for this case -->
>    <fb:on-bind>...</fb:on-bind>
>    <fb:on-insert>..</fb:on-insert>
>    <fb:on-delete>..</fb:on-delete>
> </fb:repeater>
>
> EXPECTATION DETECTION: @clear-items-on-save="true"
>
> STRATEGY on 'save':
> - remove all items using 'on-delete'
> - do as extended-case-1
>
> REMARK:
> This strategy obviously needs to delete and re-create all items. Thus it
> requires the presence of <fb:insert> and <fb:delete> bindings to operate.
> However, taking into account the current operation, and some
> typing-economics for the most logical/frequent use we should probably
> agree on some default behaviour for those and request explicit removal
> of the insert and delete bindings by adding the empty configuration
> element.

OK. As posted before (2) = extension of (1). If this is true, then we can
avoid the introduction if the new: "@clear-items-on-save". The detection
can be the same as ((1) && (<fb:on-insert/> || <fb:on-delete/>)

Because the <fb:on-insert> and <fb:on-delete> can be optional.

Suppose a form that allow a user just to insert/edit items and other form
for of the same data that allow user only delete items. ie: a very simple
ticket system when the receptionist assign new tickets and the service
personal delete them. Of course I know tickets system that store each
ticket forever (knowledge DB), but it is OT here.

>                            -o0o-
>
> [case 3]
> DESCRIPTION:
> - items have an explicit identity and can be sparsly bound
> - form-model can add/remove/reorder the rows
> - the sequence editing of the rows need to be reflected onto the items
>
> PROPOSED SYNTAX:
> <fb:repeater id="rep-id" parent-path="."
>               row-path="item" >
>    <!--required elements for this case -->
>    <fb:identity>...</fb:identity>
>    <fb:on-bind>...</fb:on-bind>
>    <fb:on-insert>..</fb:on-insert>
>    <fb:on-delete>..</fb:on-delete>
> </fb:repeater>
>
> EXPECTATION DETECTION: <fb:identity> is present
>
> STRATEGY on 'save':
> - backup all items to a list OriginalItems
> - foreach row in the repeater
>    - if row-identity-match in OriginalItems
>      - move item back into the context and bind
>    - else
>      - use on-insert and on-bind to create and bind
> - for the items still left in the OriginalItems
>    - use the on-delete

I would define <fb:on-bind> and <fb:on-delete> as optionals. Currently I
meet situations when there is a predefined list to be filled and I don't
need to add or delete row at all. Example: A user fill a form while it
fill the form the number of row of the repeater is defined. Then we use
other form for users that evaluate the filled form. In this case we
already know how many items are in the repeater (because the system
automatically build the evaluation form) and we don't allow to delete or
add new items. The evaluating user just can fill/edit the predefined
widgets in the form. No add or delete allowed. It is tipical in goverment,
when one people fill forms and other review the forms.

>                            -o0o-
>
> [case 4] (aka current RepeaterBinding)
> DESCRIPTION:
> - items have an explicit identity and can be sparsly bound
> - form-model can add/remove but should not allow reordering of the rows
> - the original sequence of the items is to be maintained at all times
> (on-insert really is more of an on-append: no new ones can be inserted
> in between the old ones)
>
> PROPOSED SYNTAX:
> not clear yet, I tend towards:
>
> <fb:repeater id="rep-id" parent-path="."
>               row-path="item"
>               row-path-insert="newItem">
>    <!--required elements for this case -->
>    <fb:identity>...</fb:identity>
>    <fb:on-bind>...</fb:on-bind>
>    <fb:on-insert>..</fb:on-insert>
>    <fb:on-delete>..</fb:on-delete>
> </fb:repeater>
>
>
> EXPECTATION DETECTION:
> fb:identity plus
> the presense of a @row-path-insert seems to indicate that the new ones
> need to go into a different space then the exisiting ones, and thus
> denying the approach expressed in case3
> (i.e. even if it would read the same as row-path! so there would be a
> difference between explicitely stating it as the same, and defaultly
> assuming it is the same)
>
>
> STRATEGY on 'save':
> - foreach row in repeater
>    - if identity match found in items
>      - bind to that
>      - add it to the set of updatedItems
>    - else
>      - add it to some list of rowsToInsert
> - run through items
>    - if NOT found in updatedItems
>      - add to list of toDeleteItems (ndx will do)
> - register the on-insert as factory
> - foreach row in rowsToInsert
>    - create and bind it
> - foreach ndx in toDeleteItems in reverse order
>    - use on-delete to remove/mark

Don't know the current RepeaterBinding do that! It distribute the result
on 3 diferent sets? It would be useful in some cases.

>                            -o0o-
>
> For completion:
> implementation of the above assumes the refactoring of the current
> identity approach towards the earlier mentioned IdentityBinding interface.
>
> see: http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=107955523607012&w=2
>
> (Joerg, if you're ok, I'll start doing it when this discussion (if any)
> converges)
>
>
> While writing up this proposal I end up questioning a number of
> (historically chosen) names that could change:
>
> - repeater/@parent-path --> repeater/@path for consistency with the
> order bindings

repeater/@base-path

> - repeater/@row-path --> repeater/@item-path since it is pointing to
> items, not rows

Here I will propose just repeater/@path. The same name as in <fb:value>.
It would be fine. While starting using Cforms I often found myself asking
by the right name. I cannot stop thinking in the repeater as a List.

> - on-insert is actually more of a on-create ('insert' seems to exclude
> 'append', while create is more nutral to exactly where the newly created
> is added, it is also more in sync with the actual factory registration
> IMHO )

+1 or on-add (it is shorter) :-P

> - repeater/@row-path-insert --> repeater/@new-item-path which would be
> syncing up with the last two changes and arguments

repeater/@new-add-path.... repeater/@add-path.... abort, retry, fail?....
Please found a name for me. Here is 2:15 a.m. I need to sleep a little
bit. :-D

Best Regards,

Antonio Gallardo

Mime
View raw message