[Agavi-Users] Validation: Provide a dependency depending on value submitted

16 views
Skip to first unread message

Michal Charemza

unread,
Sep 30, 2009, 8:37:30 AM9/30/09
to Agavi Users Mailing List
Hi,

I'm making a wizard with multiple stages, all being submitted to the
same action. The stage is in the URL like:

/somestageofwizard/
/anotherstageofwizard/

etc.

Each wizard stage has a form, and need to be validated. However, I
only want each stages' validators to run on that stage. What is the
best way of going about this?

I have tried using regex validators for "stagename": each test against
a particular stage name, and "provide" a dependency to the validators
specific to that stage. However, this always results in the
"stagename" being marked as invalid, as it can only satisfy one of the
regex validators. I would like a way to "provide" a value that is
equal to the submitted stagename: this would allow attributes like

depends="somestageofwizard"

in the validator definitions, to ensure they only run on their stage.

Is there someway to do this? Is there maybe a better way?

Michal.

_______________________________________________
users mailing list
us...@lists.agavi.org
http://lists.agavi.org/mailman/listinfo/users

Felix Gilcher

unread,
Sep 30, 2009, 9:21:01 AM9/30/09
to Agavi Users Mailing List
Why don't you use separate Actions for each stage?

felix

--
Felix Gilcher

Bitextender GmbH
Paul-Heyse-Str. 6
D-80336 München

T: +49 89 57 08 15 16
F: +49 89 57 08 15 17
M: +49 172 840 88 28

felix....@bitextender.com
http://www.bitextender.com/

Amtsgericht München, HRB 174280
Geschäftsführer: David Zülke, Florian Clever

Michal Charemza

unread,
Sep 30, 2009, 9:31:18 AM9/30/09
to Agavi Users Mailing List

On 30 Sep 2009, at 14:21, Felix Gilcher wrote:

> Why don't you use separate Actions for each stage?

I was hoping to have things a bit more general: on this site there are
in fact 2 separate wizards for different (but related) things. Plus,
each stage is presented very similarly, and goes through a very
similar action: validate the input, and go onto the next stage. It
seems a bit non DRY to have each stage as a separate action. But would
that be the preferred solution...?

Felix Gilcher

unread,
Sep 30, 2009, 9:43:27 AM9/30/09
to Agavi Users Mailing List
I think you misunderstand the DRY principle. It's not "write every
line of code only once" but "have a single point of responsibility for
every functionality", often also called "single point of truth". Since
the functionality is "validate the input for stage X in wizard Y and
then save that data" it's perfectly DRY to have a separate action for
each step of each wizard. You can always use config file inheritance
or xincludes to have common validation in a single place. You can also
use inheritance and composition to factor out common code into base
classes or models used in multiple places.

There's a pretty good writeup about DRY in german here: http://www.ruby-mine.de/2009/5/27/repeat-yourself-hin-und-wieder

felix

--
Felix Gilcher

Bitextender GmbH
Paul-Heyse-Str. 6
D-80336 München

T: +49 89 57 08 15 16
F: +49 89 57 08 15 17
M: +49 172 840 88 28

felix....@bitextender.com
http://www.bitextender.com/

Amtsgericht München, HRB 174280
Geschäftsführer: David Zülke, Florian Clever

Michal Charemza

unread,
Sep 30, 2009, 1:15:27 PM9/30/09
to Agavi Users Mailing List
Alas I can't read German..

However, I think I do disagree with what the "functionality" is in my
case. I would say the the functionality is:

"Validate the input for the current stage, save the data, and move to
the next stage"

But also: having a different action for each different stage would
make it trickier to add stages later. Right now I have that stages
defined in some simple php "config" code (order of stages, "nice"
names of stages etc...), with associated template files for the forms
themselves (It's a mild hack, but I think I can live with it). To
add / remove stages later I can edit these files. If each stage is a
different action, I would have to create a new action.

Michal.

Felix Gilcher

unread,
Oct 1, 2009, 4:55:52 AM10/1/09
to Agavi Users Mailing List
Well, that still is a fixed set of functionality that is dependent on
the stage. So you're afraid that adding stages will be difficult
because now you only need to add a template and some config. But
because you're afraid that adding stages might be difficult in the
future you have to add complicated code now. In my experience that
rarely pays of. There are certainly situations where it does, so
that's your call.

There is no way of providing a dependency depending of the value of
the incoming value, a dependency is provided if the validator returns
"true". So there's some hacks that you can use - you could have
multiple validators, one for each value. You'd have to set the
severity to "info" so that the field is not marked as "failed". That
way each validator provides a unique dependency that you can depend
on. It's a bit hacky but it should work.

felix

Michal

unread,
Oct 1, 2009, 5:42:47 AM10/1/09
to Agavi Users Mailing List
On Thu, Oct 1, 2009 at 9:55 AM, Felix Gilcher
<felix....@bitextender.com> wrote:
> Well, that still is a fixed set of functionality that is dependent on
> the stage. So you're afraid that adding stages will be difficult
> because now you only need to add a template and some config. But
> because you're afraid that adding stages might be difficult in the
> future you have to add complicated code now. In my experience that
> rarely pays of. There are certainly situations where it does, so
> that's your call.

I think I agree that it might not pay off, especially if it was very
tricky to do, but I think as a rule I like to keep in mind how to
generalise / make something "more dynamic" later. I think an action
per stage immediatly creates a stumbling block on how to generalise:
say if this were to be extended to a be a CMS where a user constructed
the wizard in a GUI.


> There is no way of providing a dependency depending of the value of
> the incoming value, a dependency is provided if the validator returns
> "true". So there's some hacks that you can use - you could have
> multiple validators, one for each value. You'd have to set the
> severity to "info" so that the field is not marked as "failed". That
> way each validator provides a unique dependency that you can depend
> on. It's a bit hacky but it should work.

That's actually less hacky than the way I've done it (and I
deliberatly don't mention the way I've done it...). I didn't know you
can set severity to "info" so it doesn't fail: that's very useful.
Thanks!

David Zülke

unread,
Oct 1, 2009, 9:40:53 AM10/1/09
to Agavi Users Mailing List
What you can do is this:

<validator class="equals" severity="info" provides="step1">
<argument>stagename</argument>
<ae:parameter name="value">stage1</ae:parameter>
</validator>
<validator class="equals" severity="info" provides="step2">
<argument>stagename</argument>
<ae:parameter name="value">stage2</ae:parameter>
</validator>
... etc, and then use depends="step1" and so forth.

However, there is a much better way that most people use:

<route name="products" pattern="^/products" module="Products">
<route name=".create" pattern="^/create">
<route pattern="^$" action="Create" />
<route name=".step1" pattern="^/step1$" action="Create"
method="step1" constraint="write" />
<route name=".step2" pattern="^/step2$" action="Create"
method="step2" constraint="write" />
</route>
</route>

Products_CreateAction::executeRead() brings up the first form and
POSTs to .step1, which will run Products_CreateAction::executeStep1();
on Success, you show the second form in there which submits to .step2,
which will run Products_CreateAction::executeStep2(), and there, in
the third form, you submit to .create (!), which will run
Products_CreateAction::executeWrite().

Keep in mind that you either need to store the intermediary step
values in a session or populate hidden fields.

This has several advantages:
- you can still POST to /products/create, e.g. for an API, without
going through the wizard steps
- all the responsibilities for actually creating the product are in
executeWrite(), so you can add other means of access (the
aforementioned API, or a SOAP interface etc etc)
- in the validation config, you can do <validators method="step1" and
so forth to group things.

Hope that helps,

David

Michal Charemza

unread,
Oct 1, 2009, 10:37:52 AM10/1/09
to Agavi Users Mailing List

On 1 Oct 2009, at 14:40, David Zülke wrote:
> <route name=".step1" pattern="^/step1$" action="Create"
> method="step1" constraint="write" />

Ah changing method is quite cunning! I didn't realise it could be
anything other than read or write. Although it does require
modification of the action for when adding stages, this does seem good
if stages are more "unique" in some way, as executeStepX method would
deal with that.

Thanks!

Reply all
Reply to author
Forward
0 new messages