[html-formfu] (ping Andreas + zby) Re: DBIC: setting accessor for a Select element triggers options_from_model()

Andreas Marienborg omega at palle.net
Thu Apr 3 21:31:44 BST 2008


On Apr 3, 2008, at 4:47 PM, Carl Franks wrote:

> On 28/02/2008, Zbigniew Lukasiak <zzbbyy at gmail.com> wrote:
>> On Wed, Feb 27, 2008 at 11:01 PM, Carl Franks  
>> <fireartist at gmail.com> wrote:
>>> On 22/02/2008, Andreas Marienborg <omega at palle.net> wrote:
>>>>
>>>> On Feb 22, 2008, at 12:08 PM, Carl Franks wrote:
>>>>
>>>>> On 21/02/2008, Steve Caldwell <info-formfu at caldwellhb.com> wrote:
>>>>>> I'm building a form that has a Select element that I'm mapping  
>>>>>> to a
>>>>>> non-column accessor on my DBIC object, as described in "non- 
>>>>>> column
>>>>>> accessors" in the HTML::FormFu::Model::DBIC POD, like this:
>>>>>>
>>>>>> ---
>>>>>> action: /foo
>>>>>> elements:
>>>>>> - type: Select
>>>>>>   name: bar
>>>>>>   label: Your Bar
>>>>>>   db:
>>>>>>     accessor: bar
>>>>>>   options:
>>>>>>     - [ 01, January ]
>>>>>>     - [ 02, February ]
>>>>>>
>>>>>> When I then try and populate it from my DBIC object:
>>>>>>
>>>>>> $form->defaults_from_model( $myobj );
>>>>>>
>>>>>> HTML::FormFu::Model::DBIC::options_from_model gets called  
>>>>>> (thanks to
>>>>>> line 44 in HTML::FormFu::Element::_Group), which then  
>>>>>> overwrites the
>>>>>> options I've set from my select list with a bunch of stuff from  
>>>>>> the
>>>>>> database.  This is obviously not what I want here.
>>>>>>
>>>>>> Anyone else come across this problem?  The work-around isn't that
>>>>>> much
>>>>>> work (manually populate from and save to my object instead of  
>>>>>> using
>>>>>> defaults_from_model() and save_to_model()), but it would be  
>>>>>> cooler
>>>>>> if it
>>>>>> all worked correctly.
>>>>>
>>>>> I agree that this is broken.
>>>>> I think Select automatically calling options_from_model() is a  
>>>>> case of
>>>>> *too much magic*
>>>>>
>>>>> (sidenote) - I know you've only just subscribed to the list, so a
>>>>> quick explanation, so that you understand my following proposal:
>>>>> FormFu in svn has been changed so that you set Model/DBIC options
>>>>> with:
>>>>>   $field->{model_config}{DBIC}
>>>>> instead of:
>>>>>   $field->{db}
>>>>>
>>>>> This will be in the next cpan release. However, setting {db} will
>>>>> still work, and Do The Right Thing, it'll just print a warning  
>>>>> that
>>>>> it's deprecated and will be removed at some point in the future.
>>>>>
>>>>> The reason for this, is the model was implemented as a bit of a
>>>>> rush-job and we need to get it working properly to support  
>>>>> multiple
>>>>> models - much like how Catalyst handles models.
>>>>> (/sidenote)
>>>>>
>>>>> I suggest we require that a new option be set to run
>>>>> options_from_model(), such as:
>>>>>
>>>>>   ---
>>>>>   element:
>>>>>     type: Select
>>>>>     name: foo
>>>>>       model_config:
>>>>>         DBIC:
>>>>>           options_from_model: 1
>>>>>
>>>>> (or, in the old, deprecated, style):
>>>>>
>>>>>   ---
>>>>>   element:
>>>>>     type: Select
>>>>>     name: foo
>>>>>       db:
>>>>>         options_from_model: 1
>>>>>
>>>>> Any opinions on this?
>>>>
>>>>
>>>> Could the default be to run it if:
>>>>
>>>> - no options_from_model: 0 (false) exists
>>>> AND
>>>> - no options already set on the select?
>>>
>>> okay, we need to revisit this :(
>>>
>>> I've moved HTML/FormFu/Model/DBIC.pm out into a separate  
>>> distribution.
>>> $form->model_class() has been renamed to default_model() and no  
>>> longer
>>> defaults to 'DBIC'.
>>> (more on that to come in another mail!)
>>>
>>> However - there's still DBIC-specific code in Element/_Group.pm to
>>> handle options_from_model()
>>> - this is bad, and needs dealt with.
>>>
>>> I can see 2 ways to deal with this:
>>>
>>> 1) Create a new system to provide hooks that model classes can  
>>> attach
>>> to, so the user doesn't need to do anything.
>>>
>>> 2) Use the hooks provided by the current plugin system, and require
>>> the user to specifically add it to the Select field.
>>> e.g.
>>>    ---
>>>    type: Select
>>>    name: foo
>>>    plugins: [ 'DBIC::LoadOptions' ]
>>>    model_config:
>>>      DBIC:
>>>        model: Foo
>>>
>>> I'm inclined to prefer solution 2, because I foresee the following
>>> problems with solution 1:
>>> - because we currently don't require the user to load the models in
>>> the form config, there's no guarantee that the model will be  
>>> available
>>> during process(), so the hooks won't get run anyway.
>>> - adding yet-more hooks will make the formfu internals more complex
>>>
>>> Any thoughts?
>>
>>
>> Here is my proposal:
>>
>> sub post_process {
>>    my $self = shift;
>>
>>    $self->next::method(@_);
>>
>>    my $args = $self->model_config;
>>
>>    # only call options_from_model if there's no options already
>>    # and {options_from_model} isn't 0
>>
>>    my $option_count = scalar @{ $self->options };
>>
>>    my $option_flag = exists $args->{options_from_model}
>>        ? $args->{options_from_model}
>>        : 1;
>>
>>    if ( $option_count == 0 && $option_flag  != 0 ) {
>>        $self->options(
>>            [ $self->form->model( $args->{model_name}
>> )->options_from_model( $self, $args ) ] );
>>    }
>> }
>
> Okay, I can dig that - lets do it!
> Do you want to make the necessary changes?
> (I'm gonna be off-line for the next week, so won't be able to do it
> until after then).
>
>> Minimal change from current.  I haven't got any intuition about using
>> multiple models in one form - but if we allow for one default model -
>> then the last significant line could be:
>> [ $self->form->model()->options_from_model( $self, $args ) ] );
>>
>> The model should know that it is a DBIC model and choose the right
>> part of $args passed to it.  Or even you could get rid of that level
>> in the hash - as it does not really make sense to have both DBIC and
>> LDAP options for one field:
>>
>> - type: Select
>>    name: type2_id
>>    model_config:
>>      DBIC:
>>        resultset: Type2
>>      LDAP:
>>        some_ldap_option: value
>>
>> Does that make sense?  I cannot imagine any situation when this would
>> be needed.  So I would say just do:
>>
>> - type: Select
>>    name: type2_id
>>    model_config:
>>      model_name: DBIC
>>      resultset: Type2
>
> Okay, I don't like it - but I'm inclined to agree that it'll be by far
> the most common usage to only use 1 model n any app - so lets make it
> easier.
>
> I don't imagine a form updating 2 different models at once, but I can
> imagine scenarios where a single element definition might have to be
> aware of 2 models.
>
> Andreas - you've been doing some LDAP model work - do you envisage any
> problems with different models sharing the same level off of  
> model_config?

  can't even see where one would use both models in the same app atm :)

Do we even need to mention the LDAP/DBIC stuff in the config?

When I do things now, I do $form->model('DBIC/LDAP')->update($item); - 
 >default_values($item) etc

so basicly the model_config should be model agnostic?

- type: Select
name: blah
model:
    resultset: BlahSet

or keep model_config as the name perhaps, as to not change too much.

- andreas



More information about the HTML-FormFu mailing list