Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Catalyst: Users

proper flow control with $c->foward, in search of greater grok

 

 

Catalyst users RSS feed   Index | Next | Previous | View Threaded


ace at tommybutler

Jan 4, 2010, 11:48 AM

Post #1 of 11 (1751 views)
Permalink
proper flow control with $c->foward, in search of greater grok

Friends,

What I know about flow control using $c->forward/detach/visit/go is
contrived at best. I'm struggling to grasp it completely due to the
various way the mechanism can be invoked, and because of the multiple
(and inconsistent) sources of information on the topic that I've found
in books and on websites (including the CPAN docs for Catalyst which
still leave a bit to be desired--at least for myself). I am looking for
something complete and exhaustive detailing every way to invoke
$c->forward. I'd also like to get some affirmation that the things I
think I understand are correct.

So the summation of what I'm looking for is:
1) are my suppositions correct as outlined below, and
2) what am I missing?

Your valued help and time is extremely appreciated.

# WHAT I (THINK) I KNOW
I understand you can invoke forward in several ways, and that it can
only ever return one value, if needed. If I also understand correctly,
should you call it without the optional final listref of extra
parameters, that the original @_ from the invoking cat action is passed
on implicitly.

# FORWARDING TO AN ACTION IN YOUR OWN NAMESPACE
$c->forward('another_action');

# FORWARDING WITH URL SYNTAX
$c->forward('/groceries/vegetables/carrots');

# FORWARDING WITH ARGUMENTS
$c->forward('yet_another_action', [ 1, 2, 'buckle my shoe' ]);

# FORWARDING TO AN ACTION IN SOME OTHER NAMESPACE
# THAT MIGHT NOT BE ACCESSIBLE AS A URL
my $dbix_query = $c->forward(
'Reports::Custom::TodaysPerformance',
'todays_performance_detailed',
[. {
report_id => $report_id,
order_by => 'record_date',
sort_order => 'ASC',
paginate => 0
} ]
);

# FORWARDING TO A VIEW?
# not sure if you can pass arguements here, nor am I sure why I'm required
# to fully qualify the namespace starting at 'MyApp' and why I am not
required
# to do so in the example immediately above this one
$c->forward('MyApp::View::MP3');

--
Tommy Butler


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


bobtfish at bobtfish

Jan 4, 2010, 12:57 PM

Post #2 of 11 (1682 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

On 4 Jan 2010, at 19:48, Tommy Butler wrote:
> # FORWARDING WITH URL SYNTAX
> $c->forward('/groceries/vegetables/carrots');
>

No, there is no such thing as forwarding to a URL.

You forward to a 'private path'. This may, or may not correspond to a
dispatchable URI.

> # FORWARDING WITH ARGUMENTS
> $c->forward('yet_another_action', [ 1, 2, 'buckle my shoe' ]);
>
> # FORWARDING TO AN ACTION IN SOME OTHER NAMESPACE
> # THAT MIGHT NOT BE ACCESSIBLE AS A URL
> my $dbix_query = $c->forward(
> 'Reports::Custom::TodaysPerformance',
> 'todays_performance_detailed',
> [ { # Snip
> } ]
> );
>

Erm, that's forwarding to a component name and a method name, and I
don't think ^^ will work, as it's not a component which will be
returned by $c->component.

> # FORWARDING TO A VIEW?
> # not sure if you can pass arguements here, nor am I sure why I'm
> required
> # to fully qualify the namespace starting at 'MyApp' and why I am not
> required
> # to do so in the example immediately above this one
> $c->forward('MyApp::View::MP3');

This is forwarding to a class name without a method name, and so the
method name defaults to 'process'

You don't fully qualify the namespace - you just say ->forward
('View::XXXX');

The other thing is that you've missed the most important and useful
thing you can forward to - an action directly.

$c->forward($c->controller('Foo')->action_for('bar'), [@args]);

Cheers
t0m


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ace at tommybutler

Jan 4, 2010, 1:26 PM

Post #3 of 11 (1683 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

Tomas Doran wrote:
>
>> # FORWARDING TO AN ACTION IN SOME OTHER NAMESPACE
>> # THAT MIGHT NOT BE ACCESSIBLE AS A URL
>> my $dbix_query = $c->forward(
>> 'Reports::Custom::TodaysPerformance',
>> 'todays_performance_detailed',
>> [ { # Snip
>> } ]
>> );
>>
>
> Erm, that's forwarding to a component name and a method name, and I
> don't think ^^ will work, as it's not a component which will be returned
> by $c->component.

I don't understand what you mean by "component", but I'll be looking
that up here momentarily. For the record, it _does_ work, and it's part
of a completely functional application running on several servers as I type.

Part of that example I found at a website and by trial and error was
able to arrive at the working final product.

>> # FORWARDING TO A VIEW?
>> # not sure if you can pass arguements here, nor am I sure why I'm
>> # required to fully qualify the namespace starting at 'MyApp' and
>> # why I am not required to do so in the example immediately above
>> # this one.
>> $c->forward('MyApp::View::MP3');
>
> This is forwarding to a class name without a method name, and so the
> method name defaults to 'process'
>
> You don't fully qualify the namespace - you just say
> ->forward('View::XXXX');

Again, this seems strange to me as well, seeing as the example I gave
for forwarding to a view comes nearly verbatim from working code. But
despite that, what you say makes perfect sense; the view (or class -ahem
, sorry) to which I'm forwarding does contain a single method named
"process". I found that example from a CPAN module's source code. As
you can see, I really have been digging around for a while. I've found
things that work, but have no idea *why*. More than anything else I've
found things that *don't* work ;-)

> The other thing is that you've missed the most important and useful
> thing you can forward to - an action directly.
>
> $c->forward($c->controller('Foo')->action_for('bar'), [@args]);

oOOooo I like that! $c->controller->... AWESOME!

Thank you for your response Tomas.

--
Tommy Butler



_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ddaupert at gmail

Jan 7, 2010, 3:20 PM

Post #4 of 11 (1609 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

On Mon, Jan 4, 2010 at 3:57 PM, Tomas Doran <bobtfish [at] bobtfish> wrote:

>
> the most important and useful thing you can forward to - an action
> directly.
>
> $c->forward($c->controller('
> Foo')->action_for('bar'), [@args]);
>

While we're on the subject, there are certain levels of grok I'd like to
attain ;-)

It seems that when chained path parts increase beyond two links, addressing
actions directly doesn't work quite as well. For example, I have these:

User.pm
User::Blog.pm
User::Blog::Entry.pm

After I add an entry to blog 'x' for user 'y', I can transport over to the
entries list for blog 'x' like so:

$c->forward($c->controller('My::Controller::User::Blog::Entry')->action_for('list'),
[ @args ]);
$c->detach;

Or less elegantly, like so:
$c->response->redirect($c->uri_for("/user/$user_id/blog/$blog_id/entry/list"));

But I can't seem to _go_ to the list (this doesn't work -- I get 'invalid
ID'):
$c->go( 'My::Controller::User::Blog::Entry', 'list', [ \@captures, \@args ]
);

Are there built-in limits to number of chained links we can dispatch by way
of directly addressing actions? Any rules/tips/guidelines in multiple
chained situations?

Thanks!

/dennis


bobtfish at bobtfish

Jan 8, 2010, 6:55 AM

Post #5 of 11 (1603 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

Dennis Daupert wrote:
> It seems that when chained path parts increase beyond two links,
> addressing actions directly doesn't work quite as well. For example, I
> have these:
>
> User.pm
> User::Blog.pm
> User::Blog::Entry.pm
>
> After I add an entry to blog 'x' for user 'y', I can transport over to
> the entries list for blog 'x' like so:
>
> $c->forward($c->controller('My::Controller::User::Blog::Entry')->action_for('list'),
> [ @args ]);
> $c->detach;

Right, but forward visits _one action_, only..

> Or less elegantly, like so:
> $c->response->redirect($c->uri_for("/user/$user_id/blog/$blog_id/entry/list"));

Eww, don't do that.

You want
$c->response->redirect($c->uri_for_action('/user/blog/entry/list',
[$user_id, $blog_id]));

And it should be noted that redirect and forward are _totally_ different
things, used for totally different purposes.

>
> But I can't seem to _go_ to the list (this doesn't work -- I get
> 'invalid ID'):
> $c->go( 'My::Controller::User::Blog::Entry', 'list', [ \@captures,
> \@args ] );

Not specific enough. You get 'invalid ID' where, from what?

Please show use the debug table from app startup and for the hit in
question which has the issue?

At a guess what you're doing wrong is not ->go ing to the end of the
chain - you can _only_ go to chain endpoints (rather than individual
actions) as go does a full redispatch.

> Are there built-in limits to number of chained links we can dispatch by
> way of directly addressing actions?

No.

> Any rules/tips/guidelines in
> multiple chained situations?

DO NOT CONSTRUCT PATHS MANUALLY.
USE ACTION OBJECTS OR uri_for_action.

That is all :)

Cheers
t0m


_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


moseley at hank

Jan 8, 2010, 7:34 AM

Post #6 of 11 (1604 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

On Fri, Jan 8, 2010 at 6:55 AM, Tomas Doran <bobtfish [at] bobtfish> wrote:

>
>
>>
>> $c->response->redirect($c->uri_for("/user/$user_id/blog/$blog_id/entry/list"));
>>
>
> Eww, don't do that.
>
> You want
> $c->response->redirect($c->uri_for_action('/user/blog/entry/list',
> [$user_id, $blog_id]));
>

I agree that's the right approach, but not sure I see why the "Eww" in this
specific case. Can you explain?



--
Bill Moseley
moseley [at] hank


bobtfish at bobtfish

Jan 8, 2010, 8:35 AM

Post #7 of 11 (1595 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

Bill Moseley wrote:
>
>
> On Fri, Jan 8, 2010 at 6:55 AM, Tomas Doran <bobtfish [at] bobtfish
> <mailto:bobtfish [at] bobtfish>> wrote:
>
>
>
> $c->response->redirect($c->uri_for("/user/$user_id/blog/$blog_id/entry/list"));
>
>
> Eww, don't do that.
>
> You want
> $c->response->redirect($c->uri_for_action('/user/blog/entry/list',
> [$user_id, $blog_id]));
>
>
> I agree that's the right approach, but not sure I see why the "Eww" in
> this specific case. Can you explain?

Yes, c->uri_for("/user/$user_id/blog/$blog_id/entry/list") is hard
coding the URI, rather than asking the dispatcher to construct it for you.

This inevitably means that you'll have to change the code when you
refactor / change the URI layout later. Hard coding the URI paths to
your controllers in multiple controllers / templates is also of course
repeating yourself more than you need to be doing.

In fact, if possible, you probably want to be saying
$c->uri_for($self->action_for('foo'), \@caps, @args);

because then you can reuse the controller code at a totally different
URI path without having to change any code at all.

Cheers
t0m

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ddaupert at gmail

Jan 8, 2010, 8:49 AM

Post #8 of 11 (1597 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

On Fri, Jan 8, 2010 at 9:55 AM, Tomas Doran <bobtfish [at] bobtfish> wrote:

>
>>
>> $c->response->redirect($c->uri_for("/user/$user_id/blog/$blog_id/entry/list"));
>>
>
> Eww, don't do that.
>

I know, I held my nose when doing that, but in point of fact, it does work,
so in a pinch....

>
> You want
> $c->response->redirect($c->uri_for_action('/user/blog/entry/list',
> [$user_id, $blog_id]));
>

For some unknown reason, I was never able to get the redirect formatting
worked out, so I resorted to smelly workarounds. That works nicely, thank
you.


>
>> But I can't seem to _go_ to the list (this doesn't work -- I get 'invalid
>> ID'):
>> $c->go( 'My::Controller::User::Blog::Entry', 'list', [ \@captures, \@args
>> ] );
>>
>
> Not specific enough. You get 'invalid ID' where, from what?
>

My bad, sorry, that's from a debug message *somebody* coded into my app
(sigh).

>
> Please show use the debug table from app startup and for the hit in
> question which has the issue?


> At a guess what you're doing wrong is not ->go ing to the end of the chain
> - you can _only_ go to chain endpoints (rather than individual actions) as
> go does a full redispatch.
>
> Actually, I am trying to go to the end of chain:

| /user/*/blog/*/entry/list | /user/base (0) |
| | -> /user/id (1) |
| | -> /user/blog/base (0) |
| | -> /user/blog/id (1) |
| | -> /user/blog/entry/base (0) |
| | => /user/blog/entry/list |


But likely I don't have the go formatting correct. He's not picking up the
user id:

.--------------------------------
| Action
+--------------------------------
| /auto
| /user/base
| /user/id
| /user/blog/base
| /user/blog/id
| /user/blog/entry/base
| /user/blog/entry/add
| -> /user/blog/entry/save
| /auto
| /user/base
| /user/id
| -> /user/not_found
| -> /user/list
| /end
| -> Blog::View::TT->process

I've tried various incarnations of go, but here's one:

my @args = qw( $user_id $blog_id );
my @captures = $c->req->captures;

$c->go( 'Blog::Controller::User::Blog::Entry', 'list', [ \@captures,
\@args ] );

I also tried with my @captures = (), @captures = qw( $user_id $blog_id );

I don't see go yet.

/dennis


pagaltzis at gmx

Jan 11, 2010, 1:00 AM

Post #9 of 11 (1495 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

* Dennis Daupert <ddaupert [at] gmail> [2010-01-08 17:50]:
> I've tried various incarnations of go, but here's one:
>
> my @args = qw( $user_id $blog_id );

Uhm, you know that `qw` does not interpolate, right? So that line
will assign the literal strings '$user_id' and '$blog_id' into
@args, not the contents of the variables $user_id and $blog_id.
That would be why your IDs are invalid… just basic Perl stuff,
nothing to do with Catalyst.

> my @captures = $c->req->captures;
>
> $c->go( 'Blog::Controller::User::Blog::Entry', 'list', [ \@captures,
> \@args ] );
>
> I also tried with my @captures = (), @captures = qw( $user_id $blog_id );
>
> I don't see go yet.

The square brackets in the POD (which I think they are a really
bad stylistic choice there) mean that these arguments are
optional, not that you should pass those parameters inside an
anonymous array. I think you are looking for

my @caps = ( $user_id, $blog_id );
$c->go( '/user/blog/entry/list', \@caps );

or just

$c->go( '/user/blog/entry/list', [ $user_id, $blog_id ] );

Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/


ddaupert at gmail

Jan 24, 2010, 9:04 AM

Post #10 of 11 (1210 views)
Permalink
Re: Re: proper flow control with $c->foward, in search of greater grok [In reply to]

My apologies...My day job heated up considerably the past couple weeks....

On Mon, Jan 11, 2010 at 4:00 AM, Aristotle Pagaltzis <pagaltzis [at] gmx>wrote:

>
> Uhm, you know that `qw` does not interpolate, right? So that line
> will assign the literal strings '$user_id' and '$blog_id' into
> @args, not the contents of the variables $user_id and $blog_id.
> That would be why your IDs are invalid… just basic Perl stuff,
> nothing to do with Catalyst.
>
> Yes, you are right of course. My bad. I tried a list of trial-and-error
attempts, and didn't notice that in *some* of them I stuck in the
non-interpolating qw.But, there still *may* be a Catalyst problem. See
below.

The square brackets in the POD (which I think they are a really
> bad stylistic choice there) mean that these arguments are
> optional, not that you should pass those parameters inside an
> anonymous array.


I hadn't realized that, I appreciate you're pointing that out.


> I think you are looking for
>
> my @caps = ( $user_id, $blog_id );
> $c->go( '/user/blog/entry/list', \@caps );
>
> or just
>
> $c->go( '/user/blog/entry/list', [ $user_id, $blog_id ] );
>
> Neither of these formats works for me. I'm getting exactly the same
behavior as I got previously. I see all the correct body parameters being
passed, but the $user_id isn't being recognized in the first leg of the
chain. However, the uri_for_action format does work:

$c->response->redirect($c->uri_for_action('/user/blog/entry/list',
[$user_id, $blog_id]));


/d


pagaltzis at gmx

Feb 6, 2010, 11:32 AM

Post #11 of 11 (1065 views)
Permalink
Re: proper flow control with $c->foward, in search of greater grok [In reply to]

* Dennis Daupert <ddaupert [at] gmail> [2010-01-24 18:05]:
> On Mon, Jan 11, 2010 at 4:00 AM, Aristotle Pagaltzis <pagaltzis [at] gmx>wrote:
> > I think you are looking for
> >
> > my @caps = ( $user_id, $blog_id );
> > $c->go( '/user/blog/entry/list', \@caps );
> >
> > or just
> >
> > $c->go( '/user/blog/entry/list', [ $user_id, $blog_id ] );
>
> Neither of these formats works for me. I'm getting exactly the
> same behavior as I got previously. I see all the correct body
> parameters being passed, but the $user_id isn't being
> recognized in the first leg of the chain. However, the
> uri_for_action format does work:
>
> $c->response->redirect($c->uri_for_action('/user/blog/entry/list',
> [$user_id, $blog_id]));

Hmm, per my reading of the documentation, the examples I gave
should work. However, I haven’t used `go` in practice yet. (I
have some places that currently do more hacky things that should
be converted to `go`, but I haven’t found the time.)

Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>

_______________________________________________
List: Catalyst [at] lists
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst [at] lists/
Dev site: http://dev.catalyst.perl.org/

Catalyst users RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.