small improves to doc/code clarity
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema.pm
CommitLineData
a02675cd 1package DBIx::Class::Schema;
2
3use strict;
4use warnings;
aa562407 5
701da8c4 6use Carp::Clan qw/^DBIx::Class/;
a917fb06 7use Scalar::Util qw/weaken/;
7cb86b38 8require Module::Find;
a02675cd 9
41a6f8c0 10use base qw/DBIx::Class/;
a02675cd 11
0dc79249 12__PACKAGE__->mk_classdata('class_mappings' => {});
13__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 14__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 15__PACKAGE__->mk_classdata('storage');
82cc0386 16__PACKAGE__->mk_classdata('exception_action');
a02675cd 17
c2da098a 18=head1 NAME
19
20DBIx::Class::Schema - composable schemas
21
22=head1 SYNOPSIS
23
24d67825 24 package Library::Schema;
c2da098a 25 use base qw/DBIx::Class::Schema/;
bab77431 26
24d67825 27 # load Library::Schema::CD, Library::Schema::Book, Library::Schema::DVD
28 __PACKAGE__->load_classes(qw/CD Book DVD/);
c2da098a 29
24d67825 30 package Library::Schema::CD;
03312470 31 use base qw/DBIx::Class/;
77254782 32 __PACKAGE__->load_components(qw/PK::Auto Core/); # for example
24d67825 33 __PACKAGE__->table('cd');
c2da098a 34
5d9076f2 35 # Elsewhere in your code:
24d67825 36 my $schema1 = Library::Schema->connect(
a3d93194 37 $dsn,
38 $user,
39 $password,
24d67825 40 { AutoCommit => 0 },
a3d93194 41 );
bab77431 42
24d67825 43 my $schema2 = Library::Schema->connect($coderef_returning_dbh);
c2da098a 44
24d67825 45 # fetch objects using Library::Schema::DVD
46 my $resultset = $schema1->resultset('DVD')->search( ... );
47 my @dvd_objects = $schema2->resultset('DVD')->search( ... );
c2da098a 48
49=head1 DESCRIPTION
50
a3d93194 51Creates database classes based on a schema. This is the recommended way to
52use L<DBIx::Class> and allows you to use more than one concurrent connection
53with your classes.
429bd4f1 54
03312470 55NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
2053ab2a 56carefully, as DBIx::Class does things a little differently. Note in
03312470 57particular which module inherits off which.
58
c2da098a 59=head1 METHODS
60
87c4e602 61=head2 register_class
62
27f01d1f 63=over 4
64
ebc77b53 65=item Arguments: $moniker, $component_class
27f01d1f 66
67=back
076652e8 68
71f9df37 69Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
2053ab2a 70calling:
66d9ef6b 71
181a28f4 72 $schema->register_source($moniker, $component_class->result_source_instance);
076652e8 73
c2da098a 74=cut
75
a02675cd 76sub register_class {
0dc79249 77 my ($self, $moniker, $to_register) = @_;
78 $self->register_source($moniker => $to_register->result_source_instance);
74b92d9a 79}
80
87c4e602 81=head2 register_source
82
27f01d1f 83=over 4
84
ebc77b53 85=item Arguments: $moniker, $result_source
27f01d1f 86
87=back
076652e8 88
82b01c38 89Registers the L<DBIx::Class::ResultSource> in the schema with the given
90moniker.
076652e8 91
92=cut
93
0dc79249 94sub register_source {
95 my ($self, $moniker, $source) = @_;
96 my %reg = %{$self->source_registrations};
97 $reg{$moniker} = $source;
98 $self->source_registrations(\%reg);
99 $source->schema($self);
a917fb06 100 weaken($source->{schema}) if ref($self);
0dc79249 101 if ($source->result_class) {
102 my %map = %{$self->class_mappings};
103 $map{$source->result_class} = $moniker;
104 $self->class_mappings(\%map);
105 }
75d07914 106}
a02675cd 107
bfb2bd4f 108=head2 class
109
27f01d1f 110=over 4
82b01c38 111
ebc77b53 112=item Arguments: $moniker
27f01d1f 113
d601dc88 114=item Return Value: $classname
27f01d1f 115
116=back
82b01c38 117
2053ab2a 118Retrieves the result class name for the given moniker. For example:
82b01c38 119
120 my $class = $schema->class('CD');
bfb2bd4f 121
122=cut
123
124sub class {
0dc79249 125 my ($self, $moniker) = @_;
126 return $self->source($moniker)->result_class;
bfb2bd4f 127}
128
ea20d0fd 129=head2 source
130
27f01d1f 131=over 4
132
ebc77b53 133=item Arguments: $moniker
27f01d1f 134
d601dc88 135=item Return Value: $result_source
82b01c38 136
27f01d1f 137=back
82b01c38 138
24d67825 139 my $source = $schema->source('Book');
ea20d0fd 140
82b01c38 141Returns the L<DBIx::Class::ResultSource> object for the registered moniker.
ea20d0fd 142
143=cut
144
145sub source {
0dc79249 146 my ($self, $moniker) = @_;
147 my $sreg = $self->source_registrations;
148 return $sreg->{$moniker} if exists $sreg->{$moniker};
149
150 # if we got here, they probably passed a full class name
151 my $mapped = $self->class_mappings->{$moniker};
701da8c4 152 $self->throw_exception("Can't find source for ${moniker}")
0dc79249 153 unless $mapped && exists $sreg->{$mapped};
154 return $sreg->{$mapped};
ea20d0fd 155}
156
0dc79249 157=head2 sources
158
27f01d1f 159=over 4
160
d601dc88 161=item Return Value: @source_monikers
27f01d1f 162
163=back
82b01c38 164
165Returns the source monikers of all source registrations on this schema.
2053ab2a 166For example:
82b01c38 167
168 my @source_monikers = $schema->sources;
0dc79249 169
170=cut
171
172sub sources { return keys %{shift->source_registrations}; }
173
ea20d0fd 174=head2 resultset
175
27f01d1f 176=over 4
177
ebc77b53 178=item Arguments: $moniker
27f01d1f 179
d601dc88 180=item Return Value: $result_set
82b01c38 181
27f01d1f 182=back
82b01c38 183
24d67825 184 my $rs = $schema->resultset('DVD');
ea20d0fd 185
82b01c38 186Returns the L<DBIx::Class::ResultSet> object for the registered moniker.
ea20d0fd 187
188=cut
189
190sub resultset {
0dc79249 191 my ($self, $moniker) = @_;
192 return $self->source($moniker)->resultset;
ea20d0fd 193}
194
87c4e602 195=head2 load_classes
196
27f01d1f 197=over 4
198
199=item Arguments: @classes?, { $namespace => [ @classes ] }+
200
201=back
076652e8 202
82b01c38 203With no arguments, this method uses L<Module::Find> to find all classes under
204the schema's namespace. Otherwise, this method loads the classes you specify
205(using L<use>), and registers them (using L</"register_class">).
076652e8 206
2053ab2a 207It is possible to comment out classes with a leading C<#>, but note that perl
208will think it's a mistake (trying to use a comment in a qw list), so you'll
209need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 210
2053ab2a 211Example:
82b01c38 212
213 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 214 # etc. (anything under the My::Schema namespace)
82b01c38 215
216 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
217 # not Other::Namespace::LinerNotes nor My::Schema::Track
218 My::Schema->load_classes(qw/ CD Artist #Track /, {
219 Other::Namespace => [qw/ Producer #LinerNotes /],
220 });
221
076652e8 222=cut
223
a02675cd 224sub load_classes {
5ce32fc1 225 my ($class, @params) = @_;
bab77431 226
5ce32fc1 227 my %comps_for;
bab77431 228
5ce32fc1 229 if (@params) {
230 foreach my $param (@params) {
231 if (ref $param eq 'ARRAY') {
232 # filter out commented entries
233 my @modules = grep { $_ !~ /^#/ } @$param;
bab77431 234
5ce32fc1 235 push (@{$comps_for{$class}}, @modules);
236 }
237 elsif (ref $param eq 'HASH') {
238 # more than one namespace possible
239 for my $comp ( keys %$param ) {
240 # filter out commented entries
241 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
242
243 push (@{$comps_for{$comp}}, @modules);
244 }
245 }
246 else {
247 # filter out commented entries
248 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
249 }
250 }
251 } else {
bc0c9800 252 my @comp = map { substr $_, length "${class}::" }
253 Module::Find::findallmod($class);
5ce32fc1 254 $comps_for{$class} = \@comp;
41a6f8c0 255 }
5ce32fc1 256
e6efde04 257 my @to_register;
258 {
259 no warnings qw/redefine/;
260 local *Class::C3::reinitialize = sub { };
261 foreach my $prefix (keys %comps_for) {
262 foreach my $comp (@{$comps_for{$prefix}||[]}) {
263 my $comp_class = "${prefix}::${comp}";
c037c03a 264 $class->ensure_class_loaded($comp_class);
bab77431 265 $comp_class->source_name($comp) unless $comp_class->source_name;
266
267 push(@to_register, [ $comp_class->source_name, $comp_class ]);
bfb2bd4f 268 }
5ce32fc1 269 }
a02675cd 270 }
e6efde04 271 Class::C3->reinitialize;
272
273 foreach my $to (@to_register) {
274 $class->register_class(@$to);
275 # if $class->can('result_source_instance');
276 }
a02675cd 277}
278
2374c5ff 279=head2 load_namespaces
280
281=over 4
282
85bd0538 283=item Arguments: %options?
2374c5ff 284
285=back
286
287This is an alternative to L</load_classes> above which assumes an alternative
25fb14bd 288layout for automatic class loading. It assumes that all source-definition
7a58f051 289classes are underneath a sub-namespace of the schema called C<Source>, any
290corresponding ResultSet classes are underneath a sub-namespace of the schema
291called C<ResultSet>, and any corresponding Result classes are underneath a
292sub-namespace of the schema called C<Result>.
2374c5ff 293
0f4ec1d2 294All of those sub-namespaces are configurable if you don't like the defaults,
25fb14bd 295via the options C<source_namespace>, C<resultset_namespace>, and
0f4ec1d2 296C<result_namespace>, respectively.
85bd0538 297
25fb14bd 298If (and only if) you specify the option C<default_resultset_class>, any found
7a58f051 299source-definition classes for which we do not find a corresponding
25fb14bd 300ResultSet class will have their C<resultset_class> set to
301C<default_resultset_class>.
0f4ec1d2 302
f017c022 303C<load_namespaces> takes care of calling C<resultset_class> and/or
304C<result_class> for you where neccessary if you didn't do it for yourself.
305
0f4ec1d2 306All of the namespace and classname options to this method are relative to
307the schema classname by default. To specify a fully-qualified name, prefix
308it with a literal C<+>.
2374c5ff 309
f017c022 310Examples:
2374c5ff 311
25fb14bd 312 # load My::Schema::Source::CD, My::Schema::Source::Artist,
2374c5ff 313 # My::Schema::ResultSet::CD, etc...
0f4ec1d2 314 My::Schema->load_namespaces;
315
316 # Override everything...
317 My::Schema->load_namespaces(
25fb14bd 318 source_namespace => 'Srcs',
0f4ec1d2 319 resultset_namespace => 'RSets',
320 result_namespace => 'Results',
25fb14bd 321 default_resultset_class => 'RSetBase',
0f4ec1d2 322 );
7a58f051 323 # In the above, if there is a My::Schema::Srcs::Foo, but no matching
25fb14bd 324 # My::Schema::RSets::Foo, then the Foo source will have its
325 # resultset_class set to My::Schema::RSetBase
2374c5ff 326
0f4ec1d2 327 # Put things in other namespaces
85bd0538 328 My::Schema->load_namespaces(
25fb14bd 329 source_namespace => '+Some::Place::Sources',
0f4ec1d2 330 resultset_namespace => '+Another::Place::RSets',
85bd0538 331 );
0f4ec1d2 332
f017c022 333If you'd like to use multiple namespaces of each type, simply use an arrayref
334of namespaces for that option. In the case that the same source-definition
335(or resultset, or result) class exists in multiple namespaces, the latter
336entries in your list of namespaces will override earlier ones.
337
338 My::Schema->load_namespaces(
339 source_namespace => [ 'Sources_C', 'Sources_B', 'Sources_A' ],
340 resultset_namespace => [ '+Some::Place::RSets', 'RSets' ],
341 );
85bd0538 342
2374c5ff 343=cut
344
f017c022 345# Pre-pends our classname to the given relative classname or
346# class namespace, unless there is a '+' prefix, which will
7a58f051 347# be stripped.
f017c022 348sub _expand_relative_name {
7a58f051 349 my ($class, $name) = @_;
350 return if !$name;
351 $name = $class . '::' . $name if ! ($name =~ s/^\+//);
352 return $name;
f017c022 353}
354
355# returns a hash of $shortname => $fullname for every package
356# found in the given namespaces ($shortname is with the $fullname's
357# namespace stripped off)
358sub _map_namespaces {
359 my ($class, @namespaces) = @_;
360
361 my @results_hash;
362 foreach my $namespace (@namespaces) {
363 push(
364 @results_hash,
365 map { (substr($_, length "${namespace}::"), $_) }
366 Module::Find::findallmod($namespace)
367 );
368 }
369
370 @results_hash;
371}
372
2374c5ff 373sub load_namespaces {
85bd0538 374 my ($class, %args) = @_;
2374c5ff 375
25fb14bd 376 my $source_namespace = delete $args{source_namespace} || 'Source';
377 my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
378 my $result_namespace = delete $args{result_namespace} || 'Result';
379 my $default_resultset_class = delete $args{default_resultset_class};
0f4ec1d2 380
25fb14bd 381 $class->throw_exception('load_namespaces: unknown option(s): '
382 . join(q{,}, map { qq{'$_'} } keys %args))
383 if scalar keys %args;
384
7a58f051 385 $default_resultset_class
386 = $class->_expand_relative_name($default_resultset_class);
f017c022 387
388 for my $arg ($source_namespace, $resultset_namespace, $result_namespace) {
389 $arg = [ $arg ] if !ref($arg) && $arg;
2374c5ff 390
f017c022 391 $class->throw_exception('load_namespaces: namespace arguments must be '
392 . 'a simple string or an arrayref')
393 if ref($arg) ne 'ARRAY';
2374c5ff 394
7a58f051 395 $_ = $class->_expand_relative_name($_) for (@$arg);
f017c022 396 }
2374c5ff 397
f017c022 398 my %sources = $class->_map_namespaces(@$source_namespace);
399 my %resultsets = $class->_map_namespaces(@$resultset_namespace);
400 my %results = $class->_map_namespaces(@$result_namespace);
0f4ec1d2 401
2374c5ff 402 my @to_register;
403 {
25fb14bd 404 no warnings 'redefine';
2374c5ff 405 local *Class::C3::reinitialize = sub { };
25fb14bd 406 use warnings 'redefine';
0f4ec1d2 407
2374c5ff 408 foreach my $source (keys %sources) {
409 my $source_class = $sources{$source};
410 $class->ensure_class_loaded($source_class);
411 $source_class->source_name($source) unless $source_class->source_name;
0f4ec1d2 412
413 my $rs_class = delete $resultsets{$source};
414 my $rs_set = $source_class->resultset_class;
25fb14bd 415 if($rs_set && $rs_set ne 'DBIx::Class::ResultSet') {
f017c022 416 if($rs_class && $rs_class ne $rs_set) {
25fb14bd 417 warn "We found ResultSet class '$rs_class' for '$source', but it seems "
418 . "that you had already set '$source' to use '$rs_set' instead";
2374c5ff 419 }
420 }
25fb14bd 421 elsif($rs_class ||= $default_resultset_class) {
422 $class->ensure_class_loaded($rs_class);
423 $source_class->resultset_class($rs_class);
0f4ec1d2 424 }
2374c5ff 425
fdcd8145 426 my $r_class = delete $results{$source};
427 if($r_class) {
428 my $r_set = $source_class->result_class;
429 if(!$r_set || $r_set eq $sources{$source}) {
430 $class->ensure_class_loaded($r_class);
431 $source_class->result_class($r_class);
432 }
f017c022 433 elsif($r_set ne $r_class) {
fdcd8145 434 warn "We found Result class '$r_class' for '$source', but it seems "
435 . "that you had already set '$source' to use '$r_set' instead";
436 }
437 }
438
2374c5ff 439 push(@to_register, [ $source_class->source_name, $source_class ]);
440 }
441 }
442
0f4ec1d2 443 foreach (sort keys %resultsets) {
444 warn "load_namespaces found ResultSet class $_ with no "
25fb14bd 445 . 'corresponding source-definition class';
2374c5ff 446 }
447
0f4ec1d2 448 foreach (sort keys %results) {
449 warn "load_namespaces found Result class $_ with no "
25fb14bd 450 . 'corresponding source-definition class';
2374c5ff 451 }
0f4ec1d2 452
fdcd8145 453 Class::C3->reinitialize;
454 $class->register_class(@$_) for (@to_register);
455
0f4ec1d2 456 return;
2374c5ff 457}
458
87c4e602 459=head2 compose_connection
460
27f01d1f 461=over 4
462
ebc77b53 463=item Arguments: $target_namespace, @db_info
429bd4f1 464
d601dc88 465=item Return Value: $new_schema
27f01d1f 466
467=back
076652e8 468
2053ab2a 469Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
470calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
471then injects the L<DBix::Class::ResultSetProxy> component and a
472resultset_instance classdata entry on all the new classes, in order to support
82b01c38 473$target_namespaces::$class->search(...) method calls.
474
475This is primarily useful when you have a specific need for class method access
476to a connection. In normal usage it is preferred to call
477L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
478on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
479more information.
54540863 480
076652e8 481=cut
482
a02675cd 483sub compose_connection {
ea20d0fd 484 my ($self, $target, @info) = @_;
80c90f5d 485 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 486 eval "require ${base};";
bc0c9800 487 $self->throw_exception
488 ("No arguments to load_classes and couldn't load ${base} ($@)")
489 if $@;
be381829 490
491 if ($self eq $target) {
492 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
493 foreach my $moniker ($self->sources) {
494 my $source = $self->source($moniker);
495 my $class = $source->result_class;
496 $self->inject_base($class, $base);
497 $class->mk_classdata(resultset_instance => $source->resultset);
498 $class->mk_classdata(class_resolver => $self);
499 }
50041f3c 500 $self->connection(@info);
be381829 501 return $self;
502 }
503
66d9ef6b 504 my $schema = $self->compose_namespace($target, $base);
ecceadff 505 {
506 no strict 'refs';
507 *{"${target}::schema"} = sub { $schema };
508 }
509
66d9ef6b 510 $schema->connection(@info);
0dc79249 511 foreach my $moniker ($schema->sources) {
512 my $source = $schema->source($moniker);
513 my $class = $source->result_class;
514 #warn "$moniker $class $source ".$source->storage;
8c49f629 515 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 516 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 517 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 518 }
519 return $schema;
e678398e 520}
521
77254782 522=head2 compose_namespace
523
27f01d1f 524=over 4
525
526=item Arguments: $target_namespace, $additional_base_class?
82b01c38 527
d601dc88 528=item Return Value: $new_schema
27f01d1f 529
530=back
13765dad 531
82b01c38 532For each L<DBIx::Class::ResultSource> in the schema, this method creates a
533class in the target namespace (e.g. $target_namespace::CD,
534$target_namespace::Artist) that inherits from the corresponding classes
535attached to the current schema.
77254782 536
82b01c38 537It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
538new $schema object. If C<$additional_base_class> is given, the new composed
539classes will inherit from first the corresponding classe from the current
540schema then the base class.
541
2053ab2a 542For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 543
544 $schema->compose_namespace('My::DB', 'Base::Class');
545 print join (', ', @My::DB::CD::ISA) . "\n";
546 print join (', ', @My::DB::Artist::ISA) ."\n";
547
2053ab2a 548will produce the output
82b01c38 549
550 My::Schema::CD, Base::Class
551 My::Schema::Artist, Base::Class
77254782 552
553=cut
554
e678398e 555sub compose_namespace {
66d9ef6b 556 my ($self, $target, $base) = @_;
557 my %reg = %{ $self->source_registrations };
11b78bd6 558 my %target;
559 my %map;
66d9ef6b 560 my $schema = $self->clone;
e9100ff7 561 {
562 no warnings qw/redefine/;
563 local *Class::C3::reinitialize = sub { };
564 foreach my $moniker ($schema->sources) {
565 my $source = $schema->source($moniker);
566 my $target_class = "${target}::${moniker}";
567 $self->inject_base(
568 $target_class => $source->result_class, ($base ? $base : ())
569 );
570 $source->result_class($target_class);
9d3d5af3 571 $target_class->result_source_instance($source)
572 if $target_class->can('result_source_instance');
e9100ff7 573 }
b7951443 574 }
e9100ff7 575 Class::C3->reinitialize();
11b78bd6 576 {
577 no strict 'refs';
1edaf6fe 578 foreach my $meth (qw/class source resultset/) {
579 *{"${target}::${meth}"} =
580 sub { shift->schema->$meth(@_) };
581 }
11b78bd6 582 }
bfb2bd4f 583 return $schema;
b7951443 584}
585
87c4e602 586=head2 setup_connection_class
587
27f01d1f 588=over 4
589
ebc77b53 590=item Arguments: $target, @info
27f01d1f 591
592=back
076652e8 593
82b01c38 594Sets up a database connection class to inject between the schema and the
595subclasses that the schema creates.
429bd4f1 596
076652e8 597=cut
598
b7951443 599sub setup_connection_class {
600 my ($class, $target, @info) = @_;
63e9583a 601 $class->inject_base($target => 'DBIx::Class::DB');
602 #$target->load_components('DB');
b7951443 603 $target->connection(@info);
604}
605
87c4e602 606=head2 connection
607
27f01d1f 608=over 4
609
ebc77b53 610=item Arguments: @args
66d9ef6b 611
d601dc88 612=item Return Value: $new_schema
27f01d1f 613
614=back
82b01c38 615
616Instantiates a new Storage object of type
617L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
618$storage->connect_info. Sets the connection in-place on the schema. See
619L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
66d9ef6b 620
621=cut
622
623sub connection {
624 my ($self, @info) = @_;
e59d3e5b 625 return $self if !@info && $self->storage;
1e10a11d 626 my $storage_class = $self->storage_type;
627 $storage_class = 'DBIx::Class::Storage'.$storage_class
628 if $storage_class =~ m/^::/;
8ef144ff 629 eval "require ${storage_class};";
bc0c9800 630 $self->throw_exception(
631 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
632 ) if $@;
82cc0386 633 my $storage = $storage_class->new($self);
66d9ef6b 634 $storage->connect_info(\@info);
635 $self->storage($storage);
636 return $self;
637}
638
87c4e602 639=head2 connect
640
27f01d1f 641=over 4
642
ebc77b53 643=item Arguments: @info
66d9ef6b 644
d601dc88 645=item Return Value: $new_schema
27f01d1f 646
647=back
82b01c38 648
649This is a convenience method. It is equivalent to calling
650$schema->clone->connection(@info). See L</connection> and L</clone> for more
651information.
66d9ef6b 652
653=cut
654
08b515f1 655sub connect { shift->clone->connection(@_) }
656
657=head2 txn_begin
658
82b01c38 659Begins a transaction (does nothing if AutoCommit is off). Equivalent to
660calling $schema->storage->txn_begin. See
661L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
08b515f1 662
663=cut
664
665sub txn_begin { shift->storage->txn_begin }
666
667=head2 txn_commit
668
82b01c38 669Commits the current transaction. Equivalent to calling
670$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
671for more information.
08b515f1 672
673=cut
674
675sub txn_commit { shift->storage->txn_commit }
676
677=head2 txn_rollback
678
82b01c38 679Rolls back the current transaction. Equivalent to calling
680$schema->storage->txn_rollback. See
681L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
08b515f1 682
683=cut
684
685sub txn_rollback { shift->storage->txn_rollback }
66d9ef6b 686
a62cf8d4 687=head2 txn_do
688
27f01d1f 689=over 4
690
ebc77b53 691=item Arguments: C<$coderef>, @coderef_args?
82b01c38 692
d601dc88 693=item Return Value: The return value of $coderef
27f01d1f 694
695=back
a62cf8d4 696
82b01c38 697Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
698returning its result (if any). If an exception is caught, a rollback is issued
699and the exception is rethrown. If the rollback fails, (i.e. throws an
700exception) an exception is thrown that includes a "Rollback failed" message.
a62cf8d4 701
702For example,
703
24d67825 704 my $author_rs = $schema->resultset('Author')->find(1);
70634260 705 my @titles = qw/Night Day It/;
a62cf8d4 706
707 my $coderef = sub {
a62cf8d4 708 # If any one of these fails, the entire transaction fails
70634260 709 $author_rs->create_related('books', {
24d67825 710 title => $_
711 }) foreach (@titles);
a62cf8d4 712
24d67825 713 return $author->books;
a62cf8d4 714 };
715
716 my $rs;
717 eval {
70634260 718 $rs = $schema->txn_do($coderef);
a62cf8d4 719 };
720
70634260 721 if ($@) { # Transaction failed
722 die "something terrible has happened!" #
723 if ($@ =~ /Rollback failed/); # Rollback failed
724
725 deal_with_failed_transaction();
a62cf8d4 726 }
727
82b01c38 728In a nested transaction (calling txn_do() from within a txn_do() coderef) only
729the outermost transaction will issue a L<DBIx::Class::Schema/"txn_commit"> on
730the Schema's storage, and txn_do() can be called in void, scalar and list
731context and it will behave as expected.
a62cf8d4 732
733=cut
734
735sub txn_do {
736 my ($self, $coderef, @args) = @_;
737
19630353 738 $self->storage or $self->throw_exception
739 ('txn_do called on $schema without storage');
171dadd7 740 ref $coderef eq 'CODE' or $self->throw_exception
741 ('$coderef must be a CODE reference');
a62cf8d4 742
743 my (@return_values, $return_value);
744
745 $self->txn_begin; # If this throws an exception, no rollback is needed
746
e7f2b7d5 747 my $wantarray = wantarray; # Need to save this since the context
75d07914 748 # inside the eval{} block is independent
749 # of the context that called txn_do()
a62cf8d4 750 eval {
82b01c38 751
24d67825 752 # Need to differentiate between scalar/list context to allow for
753 # returning a list in scalar context to get the size of the list
a62cf8d4 754 if ($wantarray) {
eeb34228 755 # list context
a62cf8d4 756 @return_values = $coderef->(@args);
eeb34228 757 } elsif (defined $wantarray) {
758 # scalar context
a62cf8d4 759 $return_value = $coderef->(@args);
eeb34228 760 } else {
761 # void context
762 $coderef->(@args);
a62cf8d4 763 }
764 $self->txn_commit;
765 };
766
767 if ($@) {
768 my $error = $@;
769
770 eval {
771 $self->txn_rollback;
772 };
773
774 if ($@) {
775 my $rollback_error = $@;
776 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
777 $self->throw_exception($error) # propagate nested rollback
75d07914 778 if $rollback_error =~ /$exception_class/;
a62cf8d4 779
bc0c9800 780 $self->throw_exception(
781 "Transaction aborted: $error. Rollback failed: ${rollback_error}"
782 );
a62cf8d4 783 } else {
784 $self->throw_exception($error); # txn failed but rollback succeeded
785 }
786 }
787
788 return $wantarray ? @return_values : $return_value;
789}
790
66d9ef6b 791=head2 clone
792
27f01d1f 793=over 4
794
d601dc88 795=item Return Value: $new_schema
27f01d1f 796
797=back
82b01c38 798
66d9ef6b 799Clones the schema and its associated result_source objects and returns the
800copy.
801
802=cut
803
804sub clone {
805 my ($self) = @_;
806 my $clone = bless({ (ref $self ? %$self : ()) }, ref $self || $self);
807 foreach my $moniker ($self->sources) {
808 my $source = $self->source($moniker);
809 my $new = $source->new($source);
810 $clone->register_source($moniker => $new);
811 }
82cc0386 812 $clone->storage->set_schema($clone) if $clone->storage;
66d9ef6b 813 return $clone;
814}
815
87c4e602 816=head2 populate
817
27f01d1f 818=over 4
819
ebc77b53 820=item Arguments: $moniker, \@data;
27f01d1f 821
822=back
a37a4697 823
824Populates the source registered with the given moniker with the supplied data.
82b01c38 825@data should be a list of listrefs -- the first containing column names, the
826second matching values.
827
828i.e.,
a37a4697 829
24d67825 830 $schema->populate('Artist', [
831 [ qw/artistid name/ ],
832 [ 1, 'Popular Band' ],
833 [ 2, 'Indie Band' ],
a62cf8d4 834 ...
835 ]);
a37a4697 836
837=cut
838
839sub populate {
840 my ($self, $name, $data) = @_;
841 my $rs = $self->resultset($name);
842 my @names = @{shift(@$data)};
84e3c114 843 my @created;
a37a4697 844 foreach my $item (@$data) {
845 my %create;
846 @create{@names} = @$item;
84e3c114 847 push(@created, $rs->create(\%create));
a37a4697 848 }
84e3c114 849 return @created;
a37a4697 850}
851
82cc0386 852=head2 exception_action
853
854=over 4
855
856=item Arguments: $code_reference
857
858=back
859
db5dc233 860If C<exception_action> is set for this class/object, L</throw_exception>
861will prefer to call this code reference with the exception as an argument,
862rather than its normal <croak> action.
863
864Your subroutine should probably just wrap the error in the exception
865object/class of your choosing and rethrow. If, against all sage advice,
866you'd like your C<exception_action> to suppress a particular exception
867completely, simply have it return true.
82cc0386 868
869Example:
870
871 package My::Schema;
872 use base qw/DBIx::Class::Schema/;
873 use My::ExceptionClass;
874 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
875 __PACKAGE__->load_classes;
876
db5dc233 877 # or:
82cc0386 878 my $schema_obj = My::Schema->connect( .... );
879 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
880
db5dc233 881 # suppress all exceptions, like a moron:
882 $schema_obj->exception_action(sub { 1 });
883
5160b401 884=head2 throw_exception
701da8c4 885
75d07914 886=over 4
82b01c38 887
ebc77b53 888=item Arguments: $message
82b01c38 889
890=back
891
892Throws an exception. Defaults to using L<Carp::Clan> to report errors from
db5dc233 893user's perspective. See L</exception_action> for details on overriding
894this method's behavior.
701da8c4 895
896=cut
897
898sub throw_exception {
82cc0386 899 my $self = shift;
db5dc233 900 croak @_ if !$self->exception_action || !$self->exception_action->(@_);
701da8c4 901}
902
ec6704d4 903=head2 deploy (EXPERIMENTAL)
1c339d71 904
82b01c38 905=over 4
906
ebc77b53 907=item Arguments: $sqlt_args
82b01c38 908
909=back
910
911Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 912
913Note that this feature is currently EXPERIMENTAL and may not work correctly
914across all databases, or fully handle complex relationships.
1c339d71 915
51bace1c 916See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>. The most
917common value for this would be C<< { add_drop_table => 1, } >> to have the SQL
918produced include a DROP TABLE statement for each table created.
919
1c339d71 920=cut
921
922sub deploy {
cb561d1a 923 my ($self, $sqltargs) = @_;
1c339d71 924 $self->throw_exception("Can't deploy without storage") unless $self->storage;
cb561d1a 925 $self->storage->deploy($self, undef, $sqltargs);
1c339d71 926}
927
c0f61310 928=head2 create_ddl_dir (EXPERIMENTAL)
929
930=over 4
931
932=item Arguments: \@databases, $version, $directory, $sqlt_args
933
934=back
935
936Creates an SQL file based on the Schema, for each of the specified
937database types, in the given directory.
938
939Note that this feature is currently EXPERIMENTAL and may not work correctly
940across all databases, or fully handle complex relationships.
941
942=cut
943
e673f011 944sub create_ddl_dir
945{
946 my $self = shift;
947
948 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
949 $self->storage->create_ddl_dir($self, @_);
950}
951
9b83fccd 952=head2 ddl_filename (EXPERIMENTAL)
953
954 my $filename = $table->ddl_filename($type, $dir, $version)
955
956Creates a filename for a SQL file based on the table class name. Not
957intended for direct end user use.
958
959=cut
960
e673f011 961sub ddl_filename
962{
963 my ($self, $type, $dir, $version) = @_;
964
965 my $filename = ref($self);
9e7b9292 966 $filename =~ s/::/-/;
e673f011 967 $filename = "$dir$filename-$version-$type.sql";
968
969 return $filename;
970}
971
a02675cd 9721;
c2da098a 973
c2da098a 974=head1 AUTHORS
975
daec44b8 976Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 977
978=head1 LICENSE
979
980You may distribute this code under the same terms as Perl itself.
981
982=cut
983