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