Component resolution in Catalyst 5.7100

LTjake on 2008-07-17T13:55:34

One of the things you'll see in the changelog for the next stable release of Catalyst, is a reworked component resolution system. By "component resolution" i mean, fetching components from view()/views(), model()/models(), controller()/controllers() and component().

Back in May I posted a message to the Catalyst-dev list describing some issues with the way it was currently working. Although I painted a slightly convoluted picture of doom and gloom -- it turns out that all is not lost; you were probably relying on an "undefined" behavior to begin with (kind of like assuming "keys %hash" will return things in a particular order).

For example, consider "MyApp" with two views: "Foo" and "Bar." Now, when you call "$c->view()" (i.e. with no arguments) what gets returned? Well, it depends. :) If you have none of the appropriate config (default_view) or stash variables (current_view, current_view_instance) set, then it's pretty much random.

If you write a test for the above, and see that "MyApp::View::Bar" is returned -- don't count on that test working in 5.7100 (the message I posted to the list has the technical details as to why). Though the test *may* continue to work, the above scenario will throw a pretty large warning:


Calling $c->view() will return a random view unless you specify one of:
* $c->config->{default_view} # the name of the default view to use
* $c->stash->{current_view} # the name of the view to use for this request
* $c->stash->{current_view_instance} # the instance of the view to use for this request
NB: in version 5.80, the "random" behavior will not work at all.

(FYI, if your application only has one view, calling "$c->view()" is considered "acceptable" and will spare you the warnings.)

A similar warning is thrown for $c->model(). $c->controller() with no arguments will continue to return the controller for the dispatched action. $c->component (sans args) will also stay the same, returning a sorted list of all component names.

Another issue I discovered while re-working the code was a failed reliance on the "regex" fallback.

Consider another "MyApp" with two views "Foo::Bar" and "Foo::Baz". What does "$c->view('Foo')" return? We've maintained backwards compatibility on this one -- it will return all matching views (order unknown). It is important to note that this returns an array, so list context is important. We've added a warning for this scenario as well:


Relying on the regexp fallback behavior for component resolution is unreliable and unsafe.
If you really want to search, pass in a regexp as the argument.

As noted above, if you truly were just searching for views, pass it a regex ("$c->view(qr{Foo})") and it will act as expected.

So, if you think you might be affected by these particular issues, test out the dev release! Don't say I didn't warn you. :)


Great!

ChrisDolan on 2008-07-18T00:58:27

This is great news. I was bitten by the regex fallback a year ago when I had a typo in my model name and Catalyst picked a related model instead. The two models were similar enough that I didn't notice for quite a while.

Oh, man

ChrisDolan on 2008-07-18T02:31:30

Oops, I tested this and found four accidental violations in my code: 3 x $c->view() and one case of model('DB::session') where I meant model('DB::sessions')

Please, could you add the $name to the warning message? I had to fire up the debugger to figure out which model was causing the actual warning in my code.

Otherwise, I'm getting a perfect success with my biggest app using SVN rev 8135 in http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Runtime/5.70/trunk (aka 5.7099_02)

Re:Oh, man

LTjake on 2008-07-18T12:30:15

SVN revision 8138 adds a new line about the value supplied. 5.70/trunk also has a couple more fixes for regexp fallback and ACCEPT_CONTEXT from component().

Thanks a lot for testing this out!