changes for 0.23 release
[catagits/Catalyst-Model-DBIC-Schema.git] / lib / Catalyst / Model / DBIC / Schema.pm
CommitLineData
ad91060a 1package Catalyst::Model::DBIC::Schema;
2
3use strict;
018eb0e2 4use warnings;
5
ffbf1967 6our $VERSION = '0.23';
018eb0e2 7
f1613faa 8use base qw/Catalyst::Model Class::Accessor::Fast Class::Data::Accessor/;
0f3de2c4 9use MRO::Compat;
10use mro 'c3';
ad91060a 11use UNIVERSAL::require;
12use Carp;
bfcd6e3d 13use Data::Dumper;
7db6da78 14require DBIx::Class;
ad91060a 15
f1613faa 16__PACKAGE__->mk_classaccessor('composed_schema');
17__PACKAGE__->mk_accessors('schema');
18
ad91060a 19=head1 NAME
20
21Catalyst::Model::DBIC::Schema - DBIx::Class::Schema Model Class
22
23=head1 SYNOPSIS
24
aabc1d75 25Manual creation of a DBIx::Class::Schema and a Catalyst::Model::DBIC::Schema:
26
27=over
28
29=item 1.
30
31Create the DBIx:Class schema in MyApp/Schema/FilmDB.pm:
32
33 package MyApp::Schema::FilmDB;
34 use base qw/DBIx::Class::Schema/;
35
36 __PACKAGE__->load_classes(qw/Actor Role/);
37
38=item 2.
39
40Create some classes for the tables in the database, for example an
41Actor in MyApp/Schema/FilmDB/Actor.pm:
42
43 package MyApp::Schema::FilmDB::Actor;
44 use base qw/DBIx::Class/
07edc53e 45
aabc1d75 46 __PACKAGE__->load_components(qw/Core/);
47 __PACKAGE__->table('actor');
07edc53e 48
aabc1d75 49 ...
50
c8ae74f8 51and a Role in MyApp/Schema/FilmDB/Role.pm:
aabc1d75 52
53 package MyApp::Schema::FilmDB::Role;
54 use base qw/DBIx::Class/
07edc53e 55
aabc1d75 56 __PACKAGE__->load_components(qw/Core/);
4a3e80e9 57 __PACKAGE__->table('role');
07edc53e 58
aabc1d75 59 ...
60
61Notice that the schema is in MyApp::Schema, not in MyApp::Model. This way it's
62usable as a standalone module and you can test/run it without Catalyst.
63
64=item 3.
65
66To expose it to Catalyst as a model, you should create a DBIC Model in
67MyApp/Model/FilmDB.pm:
68
69 package MyApp::Model::FilmDB;
70 use base qw/Catalyst::Model::DBIC::Schema/;
07edc53e 71
aabc1d75 72 __PACKAGE__->config(
73 schema_class => 'MyApp::Schema::FilmDB',
74 connect_info => [
75 "DBI:...",
76 "username",
77 "password",
78 {AutoCommit => 1}
79 ]
80 );
81
82See below for a full list of the possible config parameters.
83
84=back
85
6dec11b7 86Now you have a working Model which accesses your separate DBIC Schema. This can
aabc1d75 87be used/accessed in the normal Catalyst manner, via $c->model():
88
89 my $actor = $c->model('FilmDB::Actor')->find(1);
90
91You can also use it to set up DBIC authentication with
92Authentication::Store::DBIC in MyApp.pm:
93
94 package MyApp;
07edc53e 95
aabc1d75 96 use Catalyst qw/... Authentication::Store::DBIC/;
07edc53e 97
aabc1d75 98 ...
07edc53e 99
aabc1d75 100 __PACKAGE__->config->{authentication}{dbic} = {
101 user_class => 'FilmDB::Actor',
102 user_field => 'name',
103 password_field => 'password'
104 }
105
d52bc376 106C<< $c->model('Schema::Source') >> returns a L<DBIx::Class::ResultSet> for
107the source name parameter passed. To find out more about which methods can
108be called on a ResultSet, or how to add your own methods to it, please see
109the ResultSet documentation in the L<DBIx::Class> distribution.
aabc1d75 110
111Some examples are given below:
112
f1613faa 113 # to access schema methods directly:
114 $c->model('FilmDB')->schema->source(...);
115
116 # to access the source object, resultset, and class:
07edc53e 117 $c->model('FilmDB')->source(...);
118 $c->model('FilmDB')->resultset(...);
119 $c->model('FilmDB')->class(...);
c12b7310 120
07edc53e 121 # For resultsets, there's an even quicker shortcut:
122 $c->model('FilmDB::Actor')
123 # is the same as $c->model('FilmDB')->resultset('Actor')
ad91060a 124
f1613faa 125 # To get the composed schema for making new connections:
126 my $newconn = $c->model('FilmDB')->composed_schema->connect(...);
127
128 # Or the same thing via a convenience shortcut:
129 my $newconn = $c->model('FilmDB')->connect(...);
130
131 # or, if your schema works on different storage drivers:
132 my $newconn = $c->model('FilmDB')->composed_schema->clone();
133 $newconn->storage_type('::LDAP');
134 $newconn->connection(...);
135
136 # and again, a convenience shortcut
137 my $newconn = $c->model('FilmDB')->clone();
138 $newconn->storage_type('::LDAP');
139 $newconn->connection(...);
140
ad91060a 141=head1 DESCRIPTION
142
7b39f3f0 143This is a Catalyst Model for L<DBIx::Class::Schema>-based Models. See
ef91bcf9 144the documentation for L<Catalyst::Helper::Model::DBIC::Schema> for
145information on generating these Models via Helper scripts.
ad91060a 146
d52bc376 147When your Catalyst app starts up, a thin Model layer is created as an
148interface to your DBIC Schema. It should be clearly noted that the model
149object returned by C<< $c->model('FilmDB') >> is NOT itself a DBIC schema or
150resultset object, but merely a wrapper proving L<methods|/METHODS> to access
151the underlying schema.
152
153In addition to this model class, a shortcut class is generated for each
154source in the schema, allowing easy and direct access to a resultset of the
155corresponding type. These generated classes are even thinner than the model
156class, providing no public methods but simply hooking into Catalyst's
157model() accessor via the
158L<ACCEPT_CONTEXT|Catalyst::Component/ACCEPT_CONTEXT> mechanism. The complete
159contents of each generated class is roughly equivalent to the following:
160
161 package MyApp::Model::FilmDB::Actor
162 sub ACCEPT_CONTEXT {
163 my ($self, $c) = @_;
164 $c->model('FilmDB')->resultset('Actor');
165 }
166
167In short, there are three techniques available for obtaining a DBIC
168resultset object:
169
170 # the long way
171 my $rs = $c->model('FilmDB')->schema->resultset('Actor');
172
173 # using the shortcut method on the model object
174 my $rs = $c->model('FilmDB')->resultset('Actor');
175
176 # using the generated class directly
177 my $rs = $c->model('FilmDB::Actor');
178
c082639a 179In order to add methods to a DBIC resultset, you cannot simply add them to
180the source (row, table) definition class; you must define a separate custom
181resultset class. See L<DBIx::Class::Manual::Cookbook/"Predefined searches">
182for more info.
183
ad91060a 184=head1 CONFIG PARAMETERS
185
186=over 4
187
188=item schema_class
189
190This is the classname of your L<DBIx::Class::Schema> Schema. It needs
aabc1d75 191to be findable in C<@INC>, but it does not need to be inside the
192C<Catalyst::Model::> namespace. This parameter is required.
ad91060a 193
194=item connect_info
195
196This is an arrayref of connection parameters, which are specific to your
b9a72351 197C<storage_type> (see your storage type documentation for more details).
198If you only need one parameter (e.g. the DSN), you can just pass a string
199instead of an arrayref.
ad91060a 200
0f2fd2c0 201This is not required if C<schema_class> already has connection information
d89e6c8a 202defined inside itself (which isn't highly recommended, but can be done)
0f2fd2c0 203
7db6da78 204For L<DBIx::Class::Storage::DBI>, which is the only supported
205C<storage_type> in L<DBIx::Class> at the time of this writing, the
206parameters are your dsn, username, password, and connect options hashref.
207
018eb0e2 208See L<DBIx::Class::Storage::DBI/connect_info> for a detailed explanation
209of the arguments supported.
7db6da78 210
211Examples:
212
07edc53e 213 connect_info => [ 'dbi:Pg:dbname=mypgdb', 'postgres', '' ],
214
215 connect_info => [
216 'dbi:SQLite:dbname=foo.db',
217 {
218 on_connect_do => [
219 'PRAGMA synchronous = OFF',
220 ],
221 }
222 ],
223
224 connect_info => [
225 'dbi:Pg:dbname=mypgdb',
226 'postgres',
227 '',
228 { AutoCommit => 0 },
229 {
230 on_connect_do => [
231 'some SQL statement',
232 'another SQL statement',
233 ],
234 }
235 ],
7db6da78 236
8281c933 237Or using L<Config::General>:
238
239 <Model::FilmDB>
240 schema_class MyApp::Schema::FilmDB
241 connect_info dbi:Pg:dbname=mypgdb
242 connect_info postgres
243 connect_info
244 <connect_info>
245 AutoCommit 0
246 on_connect_do some SQL statement
247 on_connect_do another SQL statement
248 </connect_info>
249 </Model::FilmDB>
250
251or
252
253 <Model::FilmDB>
254 schema_class MyApp::Schema::FilmDB
255 connect_info dbi:SQLite:dbname=foo.db
256 </Model::FilmDB>
257
258
ad91060a 259=item storage_type
260
261Allows the use of a different C<storage_type> than what is set in your
262C<schema_class> (which in turn defaults to C<::DBI> if not set in current
f1613faa 263L<DBIx::Class>). Completely optional, and probably unnecessary for most
264people until other storage backends become available for L<DBIx::Class>.
ad91060a 265
266=back
267
268=head1 METHODS
269
270=over 4
271
272=item new
273
274Instantiates the Model based on the above-documented ->config parameters.
0f2fd2c0 275The only required parameter is C<schema_class>. C<connect_info> is
276required in the case that C<schema_class> does not already have connection
277information defined for it.
ad91060a 278
f1613faa 279=item schema
280
281Accessor which returns the connected schema being used by the this model.
282There are direct shortcuts on the model class itself for
283schema->resultset, schema->source, and schema->class.
284
285=item composed_schema
286
287Accessor which returns the composed schema, which has no connection info,
288which was used in constructing the C<schema> above. Useful for creating
289new connections based on the same schema/model. There are direct shortcuts
290from the model object for composed_schema->clone and composed_schema->connect
291
292=item clone
293
294Shortcut for ->composed_schema->clone
295
296=item connect
297
298Shortcut for ->composed_schema->connect
299
300=item source
c12b7310 301
f1613faa 302Shortcut for ->schema->source
303
304=item class
305
306Shortcut for ->schema->class
307
308=item resultset
309
310Shortcut for ->schema->resultset
311
312=item storage
313
314Provides an accessor for the connected schema's storage object.
315Used often for debugging and controlling transactions.
b8427e0b 316
ad91060a 317=back
318
319=cut
320
321sub new {
0f3de2c4 322 my $self = shift->next::method(@_);
ad91060a 323
324 my $class = ref($self);
325 my $model_name = $class;
326 $model_name =~ s/^[\w:]+::(?:Model|M):://;
327
0f2fd2c0 328 croak "->config->{schema_class} must be defined for this model"
329 unless $self->{schema_class};
ad91060a 330
331 my $schema_class = $self->{schema_class};
332
1aeb6e1e 333 $schema_class->require
f1613faa 334 or croak "Cannot load schema class '$schema_class': $@";
7db6da78 335
f1613faa 336 if( !$self->{connect_info} ) {
337 if($schema_class->storage && $schema_class->storage->connect_info) {
338 $self->{connect_info} = $schema_class->storage->connect_info;
339 }
340 else {
341 croak "Either ->config->{connect_info} must be defined for $class"
460e3ac8 342 . " or $schema_class must have connect info defined on it."
343 . " Here's what we got:\n"
f1613faa 344 . Dumper($self);
345 }
7db6da78 346 }
347
f1613faa 348 $self->composed_schema($schema_class->compose_namespace($class));
349 $self->schema($self->composed_schema->clone);
350
351 $self->schema->storage_type($self->{storage_type})
352 if $self->{storage_type};
7db6da78 353
b9a72351 354 $self->schema->connection(
355 ref $self->{connect_info} eq 'ARRAY' ?
356 @{$self->{connect_info}} :
357 $self->{connect_info}
358 );
f1613faa 359
ad91060a 360 no strict 'refs';
361 foreach my $moniker ($self->schema->sources) {
0b2a7108 362 my $classname = "${class}::$moniker";
7db6da78 363 *{"${classname}::ACCEPT_CONTEXT"} = sub {
ad91060a 364 shift;
c12b7310 365 shift->model($model_name)->resultset($moniker);
ad91060a 366 }
367 }
368
369 return $self;
370}
371
f1613faa 372sub clone { shift->composed_schema->clone(@_); }
373
374sub connect { shift->composed_schema->connect(@_); }
375
376sub storage { shift->schema->storage(@_); }
b8427e0b 377
ad91060a 378=head1 SEE ALSO
379
7b39f3f0 380General Catalyst Stuff:
381
382L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
383L<Catalyst::Response>, L<Catalyst::Helper>, L<Catalyst>,
384
385Stuff related to DBIC and this Model style:
386
387L<DBIx::Class>, L<DBIx::Class::Schema>,
ef91bcf9 388L<DBIx::Class::Schema::Loader>, L<Catalyst::Helper::Model::DBIC::Schema>
ad91060a 389
390=head1 AUTHOR
391
392Brandon L Black, C<blblack@gmail.com>
393
394=head1 COPYRIGHT
395
396This program is free software, you can redistribute it and/or modify it
397under the same terms as Perl itself.
398
399=cut
400
4011;