FAQ
Hi all,

as I've started to look at catalyst I wanted to ask how you or catalyst solves the following problems
in a "correct" oo-manner.

Szenario: I want to instanttiate a complex object of a class. This object does have many required
attributes and several other rules. The knowledge of these restrictions is lying in the object's class.
(IMHO this is the right place.)

In a web app these attributes are asked on more that one web page. (e.g. multitab/assistant).

My questions:
a) Where do I store the intermediate values of the attributes. I can't put them in the object itself
as it would generate a "invalid" object. Do I store them simply as data somewhere else? Do
I have to create a "proxy" object with lighter rules?

b) How can I verify attribute rules as early as possible in that "entering" process? Do I have to
dublicate the knowledge of the rules outside the class? (e.g. Length of String attribute less than 20)
The class itself would check such a restriction.

What ways are you going? Which is the "right" OO-way of doing it?

At the moment I really don't know where to place the input validation knowledge and where and how
to store the partly created objects. I hope it sounds not to academic, but I want to clearly seperate
the responsibilities.

Best regards
Andreas

Search Discussions

  • Rodrigo de Oliveira at Mar 27, 2009 at 4:07 pm

    My questions:
    a) Where do I store the intermediate values of the attributes. I can't put
    them in the object itself
    as it would generate a "invalid" object. Do I store them simply as data
    somewhere else? Do
    I have to create a "proxy" object with lighter rules?
    I wouldn't. Just instantiate your object at the entry controller and store
    the instance in the $c->session, or wherever you find appropiate depending
    on the object characteristics and the kind of state handling you need.

    Do your entry validation as part of the attribute checking validation, as in
    Moose:

    package MyClass;
    use Moose;
    use Moose::Util::TypeConstraints;
    subtype 'AcceptedAge' => as 'Int' => where { $_ >= 16 } => message { 'You
    must be at least 16 to use this.' };
    subtype 'NameStr' => as 'Str' => where { length($_) > 1 } => message { "What
    kinda name is '$_'?" };
    has 'name' => (is=>'rw', isa=>'NameStr', required => 1 );
    has 'age' => (is=>'rw', isa=>'AcceptedAge', required => 1 );
    has 'sex' => (is=>'rw', isa=>'Str', required => 1 );

    In your (overly-simplified) controller:

    sub submit : Local {
    $c->session->{obj} = new MyClass( $c->req->params ); # dies if
    constraint fails, so trap errors
    }

    b) How can I verify attribute rules as early as possible in that "entering"
    process? Do I have to
    dublicate the knowledge of the rules outside the class? (e.g. Length of
    String attribute less than 20)
    The class itself would check such a restriction.
    Then, just finish validating your object in the "exit" controller.

    sub wrap_it_up : Local {
    ...
    if( $c->session->{obj}->validate ) {
    ## yup
    } else {
    ## nope
    }
    }

    Back in your class, do the more complex validations:

    sub validate {
    return 1 if( ( $self->sex eq 'F' && $self->age >=16 ) ## girls
    mature earlier...
    ( $self->sex eq 'M' && $self->age >=18 ) );
    }

    What ways are you going? Which is the "right" OO-way of doing it?


    TIMTOWTDI

    At the moment I really don't know where to place the input validation
    knowledge and where and how
    to store the partly created objects. I hope it sounds not to academic, but
    I want to clearly seperate
    the responsibilities.
    Moose will give you a lot of ammo to help you with this, things such as
    coersion and roles. Check with the moosers in their maling list for further
    OO questions.

    On the other hand, if you need client-side validation, take a peek at
    HTML::FormFu, as it may help you with putting some of those rules on the
    client side. Catalyst::Model::Adaptor may also come in handy if you feel you
    need to turn your class into a model.

    -rodrigo
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/f92f7878/attachment.htm
  • Andreas Mock at Mar 27, 2009 at 5:10 pm

    -----Urspr?ngliche Nachricht-----
    Von: "Rodrigo" <rodrigolive@gmail.com>
    Gesendet: 27.03.09 17:10:47
    An: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Betreff: Re: [Catalyst] General Web- and OO-question
    Hi Rodrigo,

    thank you for answering.
    I wouldn't. Just instantiate your object at the entry controller and
    store the instance in the $c->session, or wherever you find
    appropiate depending on the object characteristics and the kind of
    state handling you need.
    But that' s my problem: One one web page I do not get all attributes I need
    to instantiate the object correctly. Simple unrealistic example. One one page
    the user can enter a "name" on the second the "age". The object can be instatiated
    if you provide a valid name and age.

    After the first page I do have the name, but not the age yet. But I can't instatiate
    the object because it throws an exception because age is not valid, isn't it?
    Or does Moose check constraints only on provided attributes. This can't be true
    with "required" attributes, can it?
    Do your entry validation as part of the attribute checking validation,
    as in Moose:
    I would like it to do so...
    What ways are you going? Which is the "right" OO-way of doing it?

    TIMTOWTDI
    I start to hate this perl slogan... ;-)
    I want a "good" way.
    Catalyst::Model::Adaptor may also come in handy if
    you feel you need to turn your class into a model.
    What do you mean with that?

    Best regards
    Andreas
  • Rodrigo de Oliveira at Mar 27, 2009 at 5:53 pm

    But that' s my problem: One one web page I do not get all attributes I need
    to instantiate the object correctly. Simple unrealistic example. One one
    page
    the user can enter a "name" on the second the "age". The object can be
    instatiated
    if you provide a valid name and age.

    Well, just instantiate an empty object then use the accessors Moose creates
    for you automagically. Accessors validate as well:

    sub start_up : Local {
    $c->session->{obj} = new MyClass();
    }
    sub submit_name : Local {
    $c->session->{obj}->name( $c->req->params->{name} );
    }
    sub submit_age : Local {
    $c->session->{obj}->age( $c->req->params->{age} );
    }

    But I can't instatiate
    the object because it throws an exception because age is not valid, isn't
    it?
    Or does Moose check constraints only on provided attributes. This can't be
    true
    with "required" attributes, can it?
    As long as the attribute is not "required => 1", no exception is thrown.

    Catalyst::Model::Adaptor may also come in handy if
    you feel you need to turn your class into a model.
    What do you mean with that?
    First, read up on the Model part of MVC, that's where most of your
    application storage should end up. Have you decided what are you going to do
    with the object once it's filled up?

    --rodrigo
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/0dcc1ed6/attachment.htm
  • Cory Watson at Mar 27, 2009 at 6:10 pm
    2009/3/27 Rodrigo <rodrigolive@gmail.com>
    But I can't instatiate
    the object because it throws an exception because age is not valid, isn't
    it?
    Or does Moose check constraints only on provided attributes. This can't be
    true
    with "required" attributes, can it?
    As long as the attribute is not "required => 1", no exception is thrown.
    I think you are missing his point. He wants to instantiate an object from
    the form, but if he uses his Moose object then the things he wants to
    validate (errors) will prevent him from getting an instance of his class.
    If "name" is required or isa 'Str' then if it gets an arrayref, he can't
    use the object (as either it missing or being the wrong type throws an
    exception).

    I don't know if this is a good idea yet, but it's fairly easy to create a
    "proxy" object for a given class, less all the validation:

    http://www.pastie.org/429140

    YMMV, but it would do what you want, as you could "promote" it to a real
    value iteratively after validation...

    --
    Cory 'G' Watson
    http://www.onemogin.com
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/5ca6906c/attachment.htm
  • Scott McWhirter at Mar 27, 2009 at 6:26 pm

    2009/3/27 Cory Watson <jheephat@gmail.com>:
    2009/3/27 Rodrigo <rodrigolive@gmail.com>
    But I can't instatiate
    the object because it throws an exception because age is not valid, isn't
    it?
    Or does Moose check constraints only on provided attributes. This can't
    be true
    with "required" attributes, can it?
    As long as the attribute is not "required => 1", no exception is thrown.
    I think you are missing his point. ?He wants to instantiate an object from
    the form, but if he uses his Moose object then the things he wants to
    validate (errors) will prevent him from getting an instance of his class.
    ?If "name" is required or isa 'Str' then if it gets an arrayref, he can't
    use the object (as either it missing or being the wrong type throws an
    exception).
    I don't know if this is a good idea yet, but it's fairly easy to create a
    "proxy" object for a given class, less all the validation:
    http://www.pastie.org/429140

    YMMV, but it would do what you want, as you could "promote" it to a real
    value iteratively after validation...
    Why try to make your objects work harder than they have to?

    If you have a multi-step process, collect all your data along each
    step then initialize your object with the data at the end. If you need
    to do validation along the way, you could reuse the moose type
    constraints in the classes meta information without constructing an
    object.


    --
    -Scott McWhirter- | -Technology Consultant-
    [ Cloudtone Studios - http://www.cloudtone.ca ]
  • Cory Watson at Mar 27, 2009 at 6:26 pm

    On Fri, Mar 27, 2009 at 1:10 PM, Cory Watson wrote:

    I don't know if this is a good idea yet, but it's fairly easy to create a
    "proxy" object for a given class, less all the validation:

    http://www.pastie.org/429140
    Oops, that doesn't work, but you get the idea.

    --
    Cory 'G' Watson
    http://www.onemogin.com
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/d0524889/attachment.htm
  • Rodrigo de Oliveira at Mar 27, 2009 at 6:29 pm

    I think you are missing his point. He wants to instantiate an object from
    the form, but if he uses his Moose object then the things he wants to
    validate (errors) will prevent him from getting an instance of his class.
    If "name" is required or isa 'Str' then if it gets an arrayref, he can't
    use the object (as either it missing or being the wrong type throws an
    exception).
    Well, if the object gets an arrayref when it was expecting an Str then he
    can't use the object and it should throw an exception.
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/dec8b26f/attachment.htm
  • Cory Watson at Mar 27, 2009 at 6:38 pm
    2009/3/27 Rodrigo <rodrigolive@gmail.com>
    I think you are missing his point. He wants to instantiate an object from
    the form, but if he uses his Moose object then the things he wants to
    validate (errors) will prevent him from getting an instance of his class.
    If "name" is required or isa 'Str' then if it gets an arrayref, he can't
    use the object (as either it missing or being the wrong type throws an
    exception).
    Well, if the object gets an arrayref when it was expecting an Str then he
    can't use the object and it should throw an exception.
    Picking this one to respond to, since Scott said the same thing.

    I think the OPs point was to it's really easy to go from request params to a
    constructed object. He seems to think this a great Way To Do Things�. His
    problem was that you can't do that if the object throws an exception when he
    tries to instantiate it. This short-circuits his intent to use the type
    constraints in Moose implicitly through the constructor.

    The replies all point to the idea of mating the params to their attributes
    and checking the constraints before instantiating. These are all great, but
    they don't solve his problem of using the object back on the form, think:

    <input type="text" value="[% obj.attribute %]"...>

    As for the OPs stated question: There's no one true way. There's a bunch of
    opinions. :)

    --
    Cory 'G' Watson
    http://www.onemogin.com
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090327/81fd6fc7/attachment.htm
  • Hans Dieter Pearcey at Mar 28, 2009 at 12:41 am

    On Fri, Mar 27, 2009 at 01:38:27PM -0500, Cory Watson wrote:
    I think the OPs point was to it's really easy to go from request params to a
    constructed object. He seems to think this a great Way To Do Things . His
    problem was that you can't do that if the object throws an exception when he
    tries to instantiate it. This short-circuits his intent to use the type
    constraints in Moose implicitly through the constructor.
    I've thought a few times about making an attribute metaclass that lets you ask
    for validity on-demand rather than always checking at object creation time; the
    problem with that is that it's a pretty big shift from how objects normally
    work, and I'm not sure what kind of subtle weird behaviors might arise.

    Another option mentioned elsewhere in the thread is a proxy object. Moose
    certainly exposes enough metainformation to make this possible, but I think
    there'd still be a good amount of fiddly work required; for example, you'd
    either have to use AUTOLOAD or generate anonymous classes on the fly, or switch
    to an explicit proxy API.

    I don't think any of this is insurmountable; the biggest reason I haven't tried
    one or all of these is that I'm lazy.

    hdp.
  • Scott McWhirter at Mar 28, 2009 at 12:52 am

    On Fri, Mar 27, 2009 at 5:41 PM, Hans Dieter Pearcey wrote:
    Another option mentioned elsewhere in the thread is a proxy object. ?Moose
    certainly exposes enough metainformation to make this possible, but I think
    there'd still be a good amount of fiddly work required; for example, you'd
    either have to use AUTOLOAD or generate anonymous classes on the fly, or switch
    to an explicit proxy API.

    I don't think any of this is insurmountable; the biggest reason I haven't tried
    one or all of these is that I'm lazy.
    No doubt someone could expand upon MooseX::Params::Validate along with
    using the metaclass for the Moose Class.


    --
    -Scott McWhirter- | -Technology Consultant-
    [ Cloudtone Studios - http://www.cloudtone.ca ]
  • Jonathan Rockway at Mar 29, 2009 at 11:58 am

    * On Fri, Mar 27 2009, Cory Watson wrote:
    I don't know if this is a good idea yet, but it's fairly easy to create a "proxy"
    object for a given class, less all the validation:
    FWIW, http://github.com/jrockway/moosex-partialobject/blob/49df9adf6b5fcecc517dc5be9439a8af75b9d455/lib/MooseX/PartialObject.pm

    Patches welcome. I hacked this together at OSCON last year, but haven't
    actually used it.

    Regards,
    Jonathan Rockway

    --
    print just => another => perl => hacker => if $,=$"
  • Andreas Mock at Mar 27, 2009 at 7:49 pm

    -----Urspr?ngliche Nachricht-----
    Von: "Scott McWhirter" <scott+catalyst@konobi.co.uk>
    Gesendet: 27.03.09 19:41:38
    An: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Betreff: Re: [Catalyst] General Web- and OO-question
    Hi Scott, hi all,

    thank you for your answers. They bring (little) light to my problem. ;-)
    Why try to make your objects work harder than they have to?

    If you have a multi-step process, collect all your data along each
    step then initialize your object with the data at the end. If you need
    to do validation along the way, you could reuse the moose type
    constraints in the classes meta information without constructing an
    object.
    This is a nice start point. The only thing I'm missing at the moment is
    the other questions: Where do I collect the data? In a simple hash?
    How can I address the type constraints related to an attribute?
    Would you persist the partly collected data to the session?

    I'm also intersted in that proxy solution. Is someone using that approach?

    Best regards
    Andreas
  • Andreas Mock at Mar 28, 2009 at 9:00 am

    -----Urspr?ngliche Nachricht-----
    Von: "Hans Dieter Pearcey" <hdp.perl.catalyst.users@weftsoar.net>
    Gesendet: 28.03.09 01:45:01
    An: catalyst@lists.scsys.co.uk
    Betreff: Re: [Catalyst] General Web- and OO-question Hi all,
    I don't think any of this is insurmountable; the biggest reason I haven't tried
    one or all of these is that I'm lazy.
    And how are you solving that problem being lazy. My first question was partly motivated
    by laziness too as I wanted to use the objects's knowledge about attribute checking
    outside the object (forms validation). The second motivations was getting a hint to
    do it in a conceptual nice way.

    So I still ask for solutions for the problem of instatiating complex objects while gathering
    informations on multiple web pages. Problems are:
    1) I may not have all required attributes at a time to instatiate an object correctly, therefor
    instatiation can't be used to validate single attributes.

    2) I can't create a "partly" valid object as storage for the meanwhile gathered attributes =>
    I need another way to store the attributes.

    I would really appreciate to hear more (real world) solutions to this dilemma.
    How are you all out there doing it in a OO-fashion?

    Thank you all.

    Best regards
    Andreas

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedMar 27, '09 at 1:10p
activeMar 29, '09 at 11:58a
posts14
users6
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2022 Grokbase