Catalyst-Manual
view release on metacpan or search on metacpan
lib/Catalyst/Manual/Intro.pod view on Meta::CPAN
Technically, within Catalyst a model is a B<component> - an instance of
the model's class belonging to the application. It is important to
stress that the lifetime of these objects is per application, not per
request.
While the model base class (L<Catalyst::Model>) provides things like
C<config> to better integrate the model into the application, sometimes
this is not enough, and the model requires access to C<$c> itself.
Situations where this need might arise include:
=over 4
=item *
Interacting with another model
=item *
Using per-request data to control behavior
=item *
Using plugins from a Model (for example L<Catalyst::Plugin::Cache>).
=back
From a style perspective it's usually considered bad form to make your
model "too smart" about things - it should worry about business logic
and leave the integration details to the controllers. If, however, you
find that it does not make sense at all to use an auxiliary controller
around the model, and the model's need to access C<$c> cannot be
sidestepped, there exists a power tool called L</ACCEPT_CONTEXT>.
=head4 Controllers
Multiple controllers are a good way to separate logical domains of your
application.
package MyApp::Controller::Login;
use base qw/Catalyst::Controller/;
sub sign_in : Path("sign-in") { }
sub new_password : Path("new-password") { }
sub sign_out : Path("sign-out") { }
package MyApp::Controller::Catalog;
use base qw/Catalyst::Controller/;
sub view : Local { }
sub list : Local { }
package MyApp::Controller::Cart;
use base qw/Catalyst::Controller/;
sub add : Local { }
sub update : Local { }
sub order : Local { }
Note that you can also supply attributes via the Controller's config so
long as you have at least one attribute on a subref to be exported
(:Action is commonly used for this) - for example the following is
equivalent to the same controller above:
package MyApp::Controller::Login;
use base qw/Catalyst::Controller/;
__PACKAGE__->config(
actions => {
'sign_in' => { Path => 'sign-in' },
'new_password' => { Path => 'new-password' },
'sign_out' => { Path => 'sign-out' },
},
);
sub sign_in : Action { }
sub new_password : Action { }
sub sign_out : Action { }
=head3 ACCEPT_CONTEXT
Whenever you call C<< $c->component("Foo") >> you get back an object - the
instance of the model. If the component supports the C<ACCEPT_CONTEXT>
method instead of returning the model itself, the return value of C<<
$model->ACCEPT_CONTEXT( $c ) >> will be used.
This means that whenever your model/view/controller needs to talk to
C<$c> it gets a chance to do this when it's needed.
A typical C<ACCEPT_CONTEXT> method will either clone the model and return one
with the context object set, or it will return a thin wrapper that contains
C<$c> and delegates to the per-application model object.
Generally it's a bad idea to expose the context object (C<$c>) in your
model or view code. Instead you use the C<ACCEPT_CONTEXT> subroutine
to grab the bits of the context object that you need, and provide
accessors to them in the model. This ensures that C<$c> is only in
scope where it is needed which reduces maintenance and debugging
headaches. So, if for example you needed two
L<Catalyst::Model::DBIC::Schema> models in the same Catalyst model
code, you might do something like this:
__PACKAGE__->mk_accessors(qw(model1_schema model2_schema));
sub ACCEPT_CONTEXT {
my ( $self, $c, @extra_arguments ) = @_;
$self = bless({ %$self,
model1_schema => $c->model('Model1')->schema,
model2_schema => $c->model('Model2')->schema
}, ref($self));
return $self;
}
This effectively treats $self as a B<prototype object> that gets a new
parameter. C<@extra_arguments> comes from any trailing arguments to
C<< $c->component( $bah, @extra_arguments ) >> (or C<< $c->model(...)
>>, C<< $c->view(...) >> etc).
( run in 0.700 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )