load_namespaces arrayref support
[dbsrgits/DBIx-Class-Historic.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
289classes to be loaded are underneath a sub-namespace of the schema called
290"Source", any corresponding ResultSet classes to be underneath a sub-namespace
291of the schema called "ResultSet", and any corresponing Result classes to be
292underneath a sub-namespace of the schema called "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
299source-definition classes that have no manually-created corresponding
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 );
25fb14bd 323 # ... and if there is a My::Schema::Srcs::Foo, but no matching
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
347# be stripped. Modifies its argument!
348sub _expand_relative_name {
349 my $class = shift;
350 return if !$_[0];
351 $_[0] = $class . '::' . $_[0] if ! ($_[0] =~ s/^\+//);
352}
353
354# returns a hash of $shortname => $fullname for every package
355# found in the given namespaces ($shortname is with the $fullname's
356# namespace stripped off)
357sub _map_namespaces {
358 my ($class, @namespaces) = @_;
359
360 my @results_hash;
361 foreach my $namespace (@namespaces) {
362 push(
363 @results_hash,
364 map { (substr($_, length "${namespace}::"), $_) }
365 Module::Find::findallmod($namespace)
366 );
367 }
368
369 @results_hash;
370}
371
2374c5ff 372sub load_namespaces {
85bd0538 373 my ($class, %args) = @_;
2374c5ff 374
25fb14bd 375 my $source_namespace = delete $args{source_namespace} || 'Source';
376 my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
377 my $result_namespace = delete $args{result_namespace} || 'Result';
378 my $default_resultset_class = delete $args{default_resultset_class};
0f4ec1d2 379
25fb14bd 380 $class->throw_exception('load_namespaces: unknown option(s): '
381 . join(q{,}, map { qq{'$_'} } keys %args))
382 if scalar keys %args;
383
f017c022 384 $class->_expand_relative_name($default_resultset_class);
385
386 for my $arg ($source_namespace, $resultset_namespace, $result_namespace) {
387 $arg = [ $arg ] if !ref($arg) && $arg;
2374c5ff 388
f017c022 389 $class->throw_exception('load_namespaces: namespace arguments must be '
390 . 'a simple string or an arrayref')
391 if ref($arg) ne 'ARRAY';
2374c5ff 392
f017c022 393 $class->_expand_relative_name($_) for (@$arg);
394 }
2374c5ff 395
f017c022 396 my %sources = $class->_map_namespaces(@$source_namespace);
397 my %resultsets = $class->_map_namespaces(@$resultset_namespace);
398 my %results = $class->_map_namespaces(@$result_namespace);
0f4ec1d2 399
2374c5ff 400 my @to_register;
401 {
25fb14bd 402 no warnings 'redefine';
2374c5ff 403 local *Class::C3::reinitialize = sub { };
25fb14bd 404 use warnings 'redefine';
0f4ec1d2 405
2374c5ff 406 foreach my $source (keys %sources) {
407 my $source_class = $sources{$source};
408 $class->ensure_class_loaded($source_class);
409 $source_class->source_name($source) unless $source_class->source_name;
0f4ec1d2 410
411 my $rs_class = delete $resultsets{$source};
412 my $rs_set = $source_class->resultset_class;
25fb14bd 413 if($rs_set && $rs_set ne 'DBIx::Class::ResultSet') {
f017c022 414 if($rs_class && $rs_class ne $rs_set) {
25fb14bd 415 warn "We found ResultSet class '$rs_class' for '$source', but it seems "
416 . "that you had already set '$source' to use '$rs_set' instead";
2374c5ff 417 }
418 }
25fb14bd 419 elsif($rs_class ||= $default_resultset_class) {
420 $class->ensure_class_loaded($rs_class);
421 $source_class->resultset_class($rs_class);
0f4ec1d2 422 }
2374c5ff 423
fdcd8145 424 my $r_class = delete $results{$source};
425 if($r_class) {
426 my $r_set = $source_class->result_class;
427 if(!$r_set || $r_set eq $sources{$source}) {
428 $class->ensure_class_loaded($r_class);
429 $source_class->result_class($r_class);
430 }
f017c022 431 elsif($r_set ne $r_class) {
fdcd8145 432 warn "We found Result class '$r_class' for '$source', but it seems "
433 . "that you had already set '$source' to use '$r_set' instead";
434 }
435 }
436
2374c5ff 437 push(@to_register, [ $source_class->source_name, $source_class ]);
438 }
439 }
440
0f4ec1d2 441 foreach (sort keys %resultsets) {
442 warn "load_namespaces found ResultSet class $_ with no "
25fb14bd 443 . 'corresponding source-definition class';
2374c5ff 444 }
445
0f4ec1d2 446 foreach (sort keys %results) {
447 warn "load_namespaces found Result class $_ with no "
25fb14bd 448 . 'corresponding source-definition class';
2374c5ff 449 }
0f4ec1d2 450
fdcd8145 451 Class::C3->reinitialize;
452 $class->register_class(@$_) for (@to_register);
453
0f4ec1d2 454 return;
2374c5ff 455}
456
87c4e602 457=head2 compose_connection
458
27f01d1f 459=over 4
460
ebc77b53 461=item Arguments: $target_namespace, @db_info
429bd4f1 462
d601dc88 463=item Return Value: $new_schema
27f01d1f 464
465=back
076652e8 466
2053ab2a 467Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
468calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
469then injects the L<DBix::Class::ResultSetProxy> component and a
470resultset_instance classdata entry on all the new classes, in order to support
82b01c38 471$target_namespaces::$class->search(...) method calls.
472
473This is primarily useful when you have a specific need for class method access
474to a connection. In normal usage it is preferred to call
475L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
476on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
477more information.
54540863 478
076652e8 479=cut
480
a02675cd 481sub compose_connection {
ea20d0fd 482 my ($self, $target, @info) = @_;
80c90f5d 483 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 484 eval "require ${base};";
bc0c9800 485 $self->throw_exception
486 ("No arguments to load_classes and couldn't load ${base} ($@)")
487 if $@;
be381829 488
489 if ($self eq $target) {
490 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
491 foreach my $moniker ($self->sources) {
492 my $source = $self->source($moniker);
493 my $class = $source->result_class;
494 $self->inject_base($class, $base);
495 $class->mk_classdata(resultset_instance => $source->resultset);
496 $class->mk_classdata(class_resolver => $self);
497 }
50041f3c 498 $self->connection(@info);
be381829 499 return $self;
500 }
501
66d9ef6b 502 my $schema = $self->compose_namespace($target, $base);
ecceadff 503 {
504 no strict 'refs';
505 *{"${target}::schema"} = sub { $schema };
506 }
507
66d9ef6b 508 $schema->connection(@info);
0dc79249 509 foreach my $moniker ($schema->sources) {
510 my $source = $schema->source($moniker);
511 my $class = $source->result_class;
512 #warn "$moniker $class $source ".$source->storage;
8c49f629 513 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 514 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 515 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 516 }
517 return $schema;
e678398e 518}
519
77254782 520=head2 compose_namespace
521
27f01d1f 522=over 4
523
524=item Arguments: $target_namespace, $additional_base_class?
82b01c38 525
d601dc88 526=item Return Value: $new_schema
27f01d1f 527
528=back
13765dad 529
82b01c38 530For each L<DBIx::Class::ResultSource> in the schema, this method creates a
531class in the target namespace (e.g. $target_namespace::CD,
532$target_namespace::Artist) that inherits from the corresponding classes
533attached to the current schema.
77254782 534
82b01c38 535It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
536new $schema object. If C<$additional_base_class> is given, the new composed
537classes will inherit from first the corresponding classe from the current
538schema then the base class.
539
2053ab2a 540For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 541
542 $schema->compose_namespace('My::DB', 'Base::Class');
543 print join (', ', @My::DB::CD::ISA) . "\n";
544 print join (', ', @My::DB::Artist::ISA) ."\n";
545
2053ab2a 546will produce the output
82b01c38 547
548 My::Schema::CD, Base::Class
549 My::Schema::Artist, Base::Class
77254782 550
551=cut
552
e678398e 553sub compose_namespace {
66d9ef6b 554 my ($self, $target, $base) = @_;
555 my %reg = %{ $self->source_registrations };
11b78bd6 556 my %target;
557 my %map;
66d9ef6b 558 my $schema = $self->clone;
e9100ff7 559 {
560 no warnings qw/redefine/;
561 local *Class::C3::reinitialize = sub { };
562 foreach my $moniker ($schema->sources) {
563 my $source = $schema->source($moniker);
564 my $target_class = "${target}::${moniker}";
565 $self->inject_base(
566 $target_class => $source->result_class, ($base ? $base : ())
567 );
568 $source->result_class($target_class);
9d3d5af3 569 $target_class->result_source_instance($source)
570 if $target_class->can('result_source_instance');
e9100ff7 571 }
b7951443 572 }
e9100ff7 573 Class::C3->reinitialize();
11b78bd6 574 {
575 no strict 'refs';
1edaf6fe 576 foreach my $meth (qw/class source resultset/) {
577 *{"${target}::${meth}"} =
578 sub { shift->schema->$meth(@_) };
579 }
11b78bd6 580 }
bfb2bd4f 581 return $schema;
b7951443 582}
583
87c4e602 584=head2 setup_connection_class
585
27f01d1f 586=over 4
587
ebc77b53 588=item Arguments: $target, @info
27f01d1f 589
590=back
076652e8 591
82b01c38 592Sets up a database connection class to inject between the schema and the
593subclasses that the schema creates.
429bd4f1 594
076652e8 595=cut
596
b7951443 597sub setup_connection_class {
598 my ($class, $target, @info) = @_;
63e9583a 599 $class->inject_base($target => 'DBIx::Class::DB');
600 #$target->load_components('DB');
b7951443 601 $target->connection(@info);
602}
603
87c4e602 604=head2 connection
605
27f01d1f 606=over 4
607
ebc77b53 608=item Arguments: @args
66d9ef6b 609
d601dc88 610=item Return Value: $new_schema
27f01d1f 611
612=back
82b01c38 613
614Instantiates a new Storage object of type
615L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
616$storage->connect_info. Sets the connection in-place on the schema. See
617L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
66d9ef6b 618
619=cut
620
621sub connection {
622 my ($self, @info) = @_;
e59d3e5b 623 return $self if !@info && $self->storage;
1e10a11d 624 my $storage_class = $self->storage_type;
625 $storage_class = 'DBIx::Class::Storage'.$storage_class
626 if $storage_class =~ m/^::/;
8ef144ff 627 eval "require ${storage_class};";
bc0c9800 628 $self->throw_exception(
629 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
630 ) if $@;
82cc0386 631 my $storage = $storage_class->new($self);
66d9ef6b 632 $storage->connect_info(\@info);
633 $self->storage($storage);
634 return $self;
635}
636
87c4e602 637=head2 connect
638
27f01d1f 639=over 4
640
ebc77b53 641=item Arguments: @info
66d9ef6b 642
d601dc88 643=item Return Value: $new_schema
27f01d1f 644
645=back
82b01c38 646
647This is a convenience method. It is equivalent to calling
648$schema->clone->connection(@info). See L</connection> and L</clone> for more
649information.
66d9ef6b 650
651=cut
652
08b515f1 653sub connect { shift->clone->connection(@_) }
654
655=head2 txn_begin
656
82b01c38 657Begins a transaction (does nothing if AutoCommit is off). Equivalent to
658calling $schema->storage->txn_begin. See
659L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
08b515f1 660
661=cut
662
663sub txn_begin { shift->storage->txn_begin }
664
665=head2 txn_commit
666
82b01c38 667Commits the current transaction. Equivalent to calling
668$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
669for more information.
08b515f1 670
671=cut
672
673sub txn_commit { shift->storage->txn_commit }
674
675=head2 txn_rollback
676
82b01c38 677Rolls back the current transaction. Equivalent to calling
678$schema->storage->txn_rollback. See
679L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
08b515f1 680
681=cut
682
683sub txn_rollback { shift->storage->txn_rollback }
66d9ef6b 684
a62cf8d4 685=head2 txn_do
686
27f01d1f 687=over 4
688
ebc77b53 689=item Arguments: C<$coderef>, @coderef_args?
82b01c38 690
d601dc88 691=item Return Value: The return value of $coderef
27f01d1f 692
693=back
a62cf8d4 694
82b01c38 695Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
696returning its result (if any). If an exception is caught, a rollback is issued
697and the exception is rethrown. If the rollback fails, (i.e. throws an
698exception) an exception is thrown that includes a "Rollback failed" message.
a62cf8d4 699
700For example,
701
24d67825 702 my $author_rs = $schema->resultset('Author')->find(1);
70634260 703 my @titles = qw/Night Day It/;
a62cf8d4 704
705 my $coderef = sub {
a62cf8d4 706 # If any one of these fails, the entire transaction fails
70634260 707 $author_rs->create_related('books', {
24d67825 708 title => $_
709 }) foreach (@titles);
a62cf8d4 710
24d67825 711 return $author->books;
a62cf8d4 712 };
713
714 my $rs;
715 eval {
70634260 716 $rs = $schema->txn_do($coderef);
a62cf8d4 717 };
718
70634260 719 if ($@) { # Transaction failed
720 die "something terrible has happened!" #
721 if ($@ =~ /Rollback failed/); # Rollback failed
722
723 deal_with_failed_transaction();
a62cf8d4 724 }
725
82b01c38 726In a nested transaction (calling txn_do() from within a txn_do() coderef) only
727the outermost transaction will issue a L<DBIx::Class::Schema/"txn_commit"> on
728the Schema's storage, and txn_do() can be called in void, scalar and list
729context and it will behave as expected.
a62cf8d4 730
731=cut
732
733sub txn_do {
734 my ($self, $coderef, @args) = @_;
735
19630353 736 $self->storage or $self->throw_exception
737 ('txn_do called on $schema without storage');
171dadd7 738 ref $coderef eq 'CODE' or $self->throw_exception
739 ('$coderef must be a CODE reference');
a62cf8d4 740
741 my (@return_values, $return_value);
742
743 $self->txn_begin; # If this throws an exception, no rollback is needed
744
e7f2b7d5 745 my $wantarray = wantarray; # Need to save this since the context
75d07914 746 # inside the eval{} block is independent
747 # of the context that called txn_do()
a62cf8d4 748 eval {
82b01c38 749
24d67825 750 # Need to differentiate between scalar/list context to allow for
751 # returning a list in scalar context to get the size of the list
a62cf8d4 752 if ($wantarray) {
eeb34228 753 # list context
a62cf8d4 754 @return_values = $coderef->(@args);
eeb34228 755 } elsif (defined $wantarray) {
756 # scalar context
a62cf8d4 757 $return_value = $coderef->(@args);
eeb34228 758 } else {
759 # void context
760 $coderef->(@args);
a62cf8d4 761 }
762 $self->txn_commit;
763 };
764
765 if ($@) {
766 my $error = $@;
767
768 eval {
769 $self->txn_rollback;
770 };
771
772 if ($@) {
773 my $rollback_error = $@;
774 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
775 $self->throw_exception($error) # propagate nested rollback
75d07914 776 if $rollback_error =~ /$exception_class/;
a62cf8d4 777
bc0c9800 778 $self->throw_exception(
779 "Transaction aborted: $error. Rollback failed: ${rollback_error}"
780 );
a62cf8d4 781 } else {
782 $self->throw_exception($error); # txn failed but rollback succeeded
783 }
784 }
785
786 return $wantarray ? @return_values : $return_value;
787}
788
66d9ef6b 789=head2 clone
790
27f01d1f 791=over 4
792
d601dc88 793=item Return Value: $new_schema
27f01d1f 794
795=back
82b01c38 796
66d9ef6b 797Clones the schema and its associated result_source objects and returns the
798copy.
799
800=cut
801
802sub clone {
803 my ($self) = @_;
804 my $clone = bless({ (ref $self ? %$self : ()) }, ref $self || $self);
805 foreach my $moniker ($self->sources) {
806 my $source = $self->source($moniker);
807 my $new = $source->new($source);
808 $clone->register_source($moniker => $new);
809 }
82cc0386 810 $clone->storage->set_schema($clone) if $clone->storage;
66d9ef6b 811 return $clone;
812}
813
87c4e602 814=head2 populate
815
27f01d1f 816=over 4
817
ebc77b53 818=item Arguments: $moniker, \@data;
27f01d1f 819
820=back
a37a4697 821
822Populates the source registered with the given moniker with the supplied data.
82b01c38 823@data should be a list of listrefs -- the first containing column names, the
824second matching values.
825
826i.e.,
a37a4697 827
24d67825 828 $schema->populate('Artist', [
829 [ qw/artistid name/ ],
830 [ 1, 'Popular Band' ],
831 [ 2, 'Indie Band' ],
a62cf8d4 832 ...
833 ]);
a37a4697 834
835=cut
836
837sub populate {
838 my ($self, $name, $data) = @_;
839 my $rs = $self->resultset($name);
840 my @names = @{shift(@$data)};
84e3c114 841 my @created;
a37a4697 842 foreach my $item (@$data) {
843 my %create;
844 @create{@names} = @$item;
84e3c114 845 push(@created, $rs->create(\%create));
a37a4697 846 }
84e3c114 847 return @created;
a37a4697 848}
849
82cc0386 850=head2 exception_action
851
852=over 4
853
854=item Arguments: $code_reference
855
856=back
857
db5dc233 858If C<exception_action> is set for this class/object, L</throw_exception>
859will prefer to call this code reference with the exception as an argument,
860rather than its normal <croak> action.
861
862Your subroutine should probably just wrap the error in the exception
863object/class of your choosing and rethrow. If, against all sage advice,
864you'd like your C<exception_action> to suppress a particular exception
865completely, simply have it return true.
82cc0386 866
867Example:
868
869 package My::Schema;
870 use base qw/DBIx::Class::Schema/;
871 use My::ExceptionClass;
872 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
873 __PACKAGE__->load_classes;
874
db5dc233 875 # or:
82cc0386 876 my $schema_obj = My::Schema->connect( .... );
877 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
878
db5dc233 879 # suppress all exceptions, like a moron:
880 $schema_obj->exception_action(sub { 1 });
881
5160b401 882=head2 throw_exception
701da8c4 883
75d07914 884=over 4
82b01c38 885
ebc77b53 886=item Arguments: $message
82b01c38 887
888=back
889
890Throws an exception. Defaults to using L<Carp::Clan> to report errors from
db5dc233 891user's perspective. See L</exception_action> for details on overriding
892this method's behavior.
701da8c4 893
894=cut
895
896sub throw_exception {
82cc0386 897 my $self = shift;
db5dc233 898 croak @_ if !$self->exception_action || !$self->exception_action->(@_);
701da8c4 899}
900
ec6704d4 901=head2 deploy (EXPERIMENTAL)
1c339d71 902
82b01c38 903=over 4
904
ebc77b53 905=item Arguments: $sqlt_args
82b01c38 906
907=back
908
909Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 910
911Note that this feature is currently EXPERIMENTAL and may not work correctly
912across all databases, or fully handle complex relationships.
1c339d71 913
51bace1c 914See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>. The most
915common value for this would be C<< { add_drop_table => 1, } >> to have the SQL
916produced include a DROP TABLE statement for each table created.
917
1c339d71 918=cut
919
920sub deploy {
cb561d1a 921 my ($self, $sqltargs) = @_;
1c339d71 922 $self->throw_exception("Can't deploy without storage") unless $self->storage;
cb561d1a 923 $self->storage->deploy($self, undef, $sqltargs);
1c339d71 924}
925
c0f61310 926=head2 create_ddl_dir (EXPERIMENTAL)
927
928=over 4
929
930=item Arguments: \@databases, $version, $directory, $sqlt_args
931
932=back
933
934Creates an SQL file based on the Schema, for each of the specified
935database types, in the given directory.
936
937Note that this feature is currently EXPERIMENTAL and may not work correctly
938across all databases, or fully handle complex relationships.
939
940=cut
941
e673f011 942sub create_ddl_dir
943{
944 my $self = shift;
945
946 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
947 $self->storage->create_ddl_dir($self, @_);
948}
949
9b83fccd 950=head2 ddl_filename (EXPERIMENTAL)
951
952 my $filename = $table->ddl_filename($type, $dir, $version)
953
954Creates a filename for a SQL file based on the table class name. Not
955intended for direct end user use.
956
957=cut
958
e673f011 959sub ddl_filename
960{
961 my ($self, $type, $dir, $version) = @_;
962
963 my $filename = ref($self);
9e7b9292 964 $filename =~ s/::/-/;
e673f011 965 $filename = "$dir$filename-$version-$type.sql";
966
967 return $filename;
968}
969
a02675cd 9701;
c2da098a 971
c2da098a 972=head1 AUTHORS
973
daec44b8 974Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 975
976=head1 LICENSE
977
978You may distribute this code under the same terms as Perl itself.
979
980=cut
981