File Coverage

blib/lib/Catalyst/Model/Adaptor.pm
Criterion Covered Total %
statement 12 21 57.1
branch 0 4 0.0
condition 0 2 0.0
subroutine 4 5 80.0
pod 1 1 100.0
total 17 33 51.5


line stmt bran cond sub pod time code
1             package Catalyst::Model::Adaptor;
2 1     1   18564 use strict;
  1         3  
  1         73  
3 1     1   6 use warnings;
  1         2  
  1         39  
4 1     1   5 use MRO::Compat;
  1         2  
  1         828  
5              
6 1     1   9 use base 'Catalyst::Model::Adaptor::Base';
  1         2  
  1         908  
7              
8             our $VERSION = '0.10';
9              
10             sub COMPONENT {
11 0     0 1   my ($class, $app, @rest) = @_;
12 0           my $arg = {};
13 0 0         if ( scalar @rest ) {
14 0 0         if ( ref($rest[0]) eq 'HASH' ) {
15 0           $arg = $rest[0];
16             }
17             else {
18 0           $arg = { @rest };
19             }
20             }
21 0           my $self = $class->next::method($app, $arg);
22              
23 0           $self->_load_adapted_class;
24 0   0       return $self->_create_instance(
25             $app, $class->merge_config_hashes($class->config || {}, $arg)
26             );
27             }
28              
29             1;
30             __END__
31              
32             =head1 NAME
33              
34             Catalyst::Model::Adaptor - use a plain class as a Catalyst model
35              
36             =head1 SYNOPSIS
37              
38             Given a good old perl class like:
39              
40             package NotMyApp::SomeClass;
41             use Moose; # to provide "new"
42             sub method { 'yay' }
43              
44             Wrap it with a Catalyst model:
45              
46             package MyApp::Model::SomeClass;
47             use base 'Catalyst::Model::Adaptor';
48             __PACKAGE__->config( class => 'NotMyApp::SomeClass' );
49              
50             Then you can use C<NotMyApp::SomeClass> from your Catalyst app:
51              
52             sub action :Whatever {
53             my ($self, $c) = @_;
54             my $someclass = $c->model('SomeClass');
55             $someclass->method; # yay
56             }
57              
58             Note that C<NotMyApp::SomeClass> is instantiated at application startup
59             time. If you want the adapted class to be created for call to C<<
60             $c->model >>, see L<Catalyst::Model::Factory> instead. If you want
61             the adapted class to be created once per request, see
62             L<Catalyst::Model::Factory::PerRequest>.
63              
64             =head1 DESCRIPTION
65              
66             The idea is that you don't want your Catalyst model to be anything
67             other than a line or two of glue. Using this module ensures that your
68             Model classes are separate from your application and therefore are
69             well-abstracted, reusable, and easily testable.
70              
71             Right now there are too many modules on CPAN that are
72             Catalyst-specific. Most of the models would be better written as a class
73             that handles most of the functionality with just a bit of glue to make it
74             work nicely with Catalyst. This module aims to make integrating your class
75             with Catalyst trivial, so you won't have to do any extra work to make
76             your model generic.
77              
78             For a good example of a Model that takes the right design approach,
79             take a look at
80             L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>. All
81             it does is glues an existing
82             L<DBIx::Class::Schema|DBIx::Class::Schema> to Catalyst. It provides a
83             bit of sugar, but no actual functionality. Everything important
84             happens in the C<DBIx::Class::Schema> object.
85              
86             The end result of that is that you can use your app's DBIC schema without
87             ever thinking about Catalyst. This is a Good Thing.
88              
89             Catalyst is glue, not a way of life!
90              
91             =head1 CONFIGURATION
92              
93             Subclasses of this model accept the following configuration keys, which
94             can be hard-coded like:
95              
96             package MyApp::Model::SomeClass;
97             use base 'Catalyst::Model::Adaptor';
98             __PACKAGE__->config( class => 'NotMyApp::SomeClass' );
99              
100             Or be specified as application config:
101              
102             package MyApp;
103             MyApp->config->{'Model::SomeClass'} = { class => 'NotMyApp::SomeClass' };
104              
105             Or in your ConfigLoader-loaded config file:
106              
107             ---
108             Model::SomeClass:
109             class: NotMyApp::SomeClass
110             args:
111             foo: ...
112             bar: ...
113              
114             This is exactly like every other Catalyst component, so you should
115             already know this.
116              
117             Anyway, here are the options:
118              
119             =head2 class
120              
121             This is the name of the class you're adapting to Catalyst. It MUST be
122             specified.
123              
124             Your application will die horribly if it can't require this package.
125              
126             =head2 constructor
127              
128             This is the name of the class method in C<class> that will create an
129             instance of the class. It defaults to C<new>.
130              
131             Your application will die horribly if it can't call this method.
132              
133             =head2 args
134              
135             This is a hashref of arguments to pass to the constructor of C<class>.
136             It is optional, of course. If you omit it, nothing is passed to the
137             constructor (as opposed to C<{}>, an empty hashref).
138              
139             =head1 METHODS
140              
141             There are no methods that you call directly. When you call C<<
142             $c->model >> on a model that subclasses this, you'll get back an
143             instance of the class being adapted, not this model.
144              
145             These methods are called by Catalyst:
146              
147             =head2 COMPONENT
148              
149             Setup this component.
150              
151             =head1 CUSTOMIZING THE PROCESS
152              
153             By default, the instance of your adapted class is instantiated like
154             this:
155              
156             my $args = $self->prepare_arguments($app); # $app sometimes called $c
157             $adapted_class->$constructor($self->mangle_arguments($args));
158              
159             Since a static hashref of arguments may not be what C<$class> needs,
160             you can override the following methods to change what C<$args> is.
161              
162             NOTE: If you need to pass some args at instance time, you can do something
163             like:
164              
165             my $model = $c->model('MyFoo', { foo => 'myfoo' });
166              
167             or
168              
169             my $model = $c->model('MyFoo', foo => 'myfoo');
170              
171             =head2 prepare_arguments
172              
173             This method is passed the entire configuration for the class and the
174             Catalyst application, and returns the hashref of arguments to be
175             passed to the constructor. If you need to get dynamic data out of
176             your application to pass to the consturctor, do it here.
177              
178             By default, this method returns the C<args> configuration key.
179              
180             Example:
181              
182             sub prepare_arguments {
183             my ($self, $app) = @_; # $app sometimes written as $c
184             return { foobar => $app->config->{foobar}, baz => $self->{baz} };
185             }
186              
187             =head2 mangle_arguments
188              
189             This method is passed the hashref from C<prepare_arguments>, mangles
190             them into a form that your constructor will like, and returns the
191             mangled form. If your constuctor wants a list instead of a hashref,
192             this is your opportunity to do the conversion.
193              
194             Example:
195              
196             sub mangle_arguments {
197             my ($self, $args) = @_;
198             return %$args; # now the args are a plain list
199             }
200              
201             If you need to do more than this, you might as well just write
202             the whole class yourself. This module is designed to make the common
203             case work with 1 line of code. For special needs, it's easier to just
204             write the model yourself.
205              
206             =head1 SEE ALSO
207              
208             If you need a new instance returned each time C<< $c->model >> is called,
209             use L<Catalyst::Model::Factory|Catalyst::Model::Factory> instead.
210              
211             If you need to have exactly one instance created per request, use
212             L<Catalyst::Model::Factory::PerRequest|Catalyst::Model::Factory::PerRequest>
213             instead.
214              
215             =head1 AUTHOR
216              
217             Jonathan Rockway C<< <jrockway@cpan.org> >>
218              
219             =head1 CONTRIBUTORS
220              
221             Wallace Reis C<< <wreis@cpan.org> >>
222              
223             =head1 LICENSE
224              
225             This module is Copyright (c) 2007 Jonathan Rockway. You may use,
226             modify, and redistribute it under the same terms as Perl itself.