Cleanup C3 handling, require updated Class::C3::Componentised
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema.pm
CommitLineData
a02675cd 1package DBIx::Class::Schema;
2
3use strict;
4use warnings;
aa562407 5
4981dc70 6use DBIx::Class::Exception;
c3e9f718 7use Carp::Clan qw/^DBIx::Class|^Try::Tiny/;
9780718f 8use Try::Tiny;
6298a324 9use Scalar::Util 'weaken';
c9d2e0a2 10use File::Spec;
6298a324 11use Sub::Name 'subname';
329d7385 12use Module::Find();
6298a324 13use Storable();
50261284 14use B qw/svref_2object/;
fd323bf1 15use namespace::clean;
a02675cd 16
41a6f8c0 17use base qw/DBIx::Class/;
a02675cd 18
0dc79249 19__PACKAGE__->mk_classdata('class_mappings' => {});
20__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 21__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 22__PACKAGE__->mk_classdata('storage');
82cc0386 23__PACKAGE__->mk_classdata('exception_action');
4b946902 24__PACKAGE__->mk_classdata('stacktrace' => $ENV{DBIC_TRACE} || 0);
e6c747fd 25__PACKAGE__->mk_classdata('default_resultset_attributes' => {});
a02675cd 26
c2da098a 27=head1 NAME
28
29DBIx::Class::Schema - composable schemas
30
31=head1 SYNOPSIS
32
24d67825 33 package Library::Schema;
c2da098a 34 use base qw/DBIx::Class::Schema/;
bab77431 35
829517d4 36 # load all Result classes in Library/Schema/Result/
37 __PACKAGE__->load_namespaces();
c2da098a 38
829517d4 39 package Library::Schema::Result::CD;
d88ecca6 40 use base qw/DBIx::Class::Core/;
41
42 __PACKAGE__->load_components(qw/InflateColumn::DateTime/); # for example
24d67825 43 __PACKAGE__->table('cd');
c2da098a 44
5d9076f2 45 # Elsewhere in your code:
24d67825 46 my $schema1 = Library::Schema->connect(
a3d93194 47 $dsn,
48 $user,
49 $password,
ef131d82 50 { AutoCommit => 1 },
a3d93194 51 );
bab77431 52
24d67825 53 my $schema2 = Library::Schema->connect($coderef_returning_dbh);
c2da098a 54
829517d4 55 # fetch objects using Library::Schema::Result::DVD
24d67825 56 my $resultset = $schema1->resultset('DVD')->search( ... );
57 my @dvd_objects = $schema2->resultset('DVD')->search( ... );
c2da098a 58
59=head1 DESCRIPTION
60
a3d93194 61Creates database classes based on a schema. This is the recommended way to
62use L<DBIx::Class> and allows you to use more than one concurrent connection
63with your classes.
429bd4f1 64
03312470 65NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
2053ab2a 66carefully, as DBIx::Class does things a little differently. Note in
03312470 67particular which module inherits off which.
68
829517d4 69=head1 SETUP METHODS
c2da098a 70
829517d4 71=head2 load_namespaces
87c4e602 72
27f01d1f 73=over 4
74
829517d4 75=item Arguments: %options?
27f01d1f 76
77=back
076652e8 78
829517d4 79 __PACKAGE__->load_namespaces();
66d9ef6b 80
829517d4 81 __PACKAGE__->load_namespaces(
82 result_namespace => 'Res',
83 resultset_namespace => 'RSet',
84 default_resultset_class => '+MyDB::Othernamespace::RSet',
85 );
076652e8 86
829517d4 87With no arguments, this method uses L<Module::Find> to load all your
88Result classes from a sub-namespace F<Result> under your Schema class'
48580715 89namespace, i.e. with a Schema of I<MyDB::Schema> all files in
829517d4 90I<MyDB::Schema::Result> are assumed to be Result classes.
c2da098a 91
829517d4 92It also finds all ResultSet classes in the namespace F<ResultSet> and
93loads them into the appropriate Result classes using for you. The
94matching is done by assuming the package name of the ResultSet class
95is the same as that of the Result class.
74b92d9a 96
672687db 97You will be warned if ResultSet classes are discovered for which there
829517d4 98are no matching Result classes like this:
87c4e602 99
829517d4 100 load_namespaces found ResultSet class $classname with no corresponding Result class
27f01d1f 101
829517d4 102If a Result class is found to already have a ResultSet class set using
103L</resultset_class> to some other class, you will be warned like this:
27f01d1f 104
fd323bf1 105 We found ResultSet class '$rs_class' for '$result', but it seems
829517d4 106 that you had already set '$result' to use '$rs_set' instead
076652e8 107
829517d4 108Both of the sub-namespaces are configurable if you don't like the defaults,
109via the options C<result_namespace> and C<resultset_namespace>.
076652e8 110
829517d4 111If (and only if) you specify the option C<default_resultset_class>, any found
112Result classes for which we do not find a corresponding
113ResultSet class will have their C<resultset_class> set to
114C<default_resultset_class>.
076652e8 115
829517d4 116All of the namespace and classname options to this method are relative to
117the schema classname by default. To specify a fully-qualified name, prefix
118it with a literal C<+>.
2a4d9487 119
829517d4 120Examples:
2a4d9487 121
829517d4 122 # load My::Schema::Result::CD, My::Schema::Result::Artist,
123 # My::Schema::ResultSet::CD, etc...
124 My::Schema->load_namespaces;
2a4d9487 125
829517d4 126 # Override everything to use ugly names.
127 # In this example, if there is a My::Schema::Res::Foo, but no matching
128 # My::Schema::RSets::Foo, then Foo will have its
129 # resultset_class set to My::Schema::RSetBase
130 My::Schema->load_namespaces(
131 result_namespace => 'Res',
132 resultset_namespace => 'RSets',
133 default_resultset_class => 'RSetBase',
134 );
2a4d9487 135
829517d4 136 # Put things in other namespaces
137 My::Schema->load_namespaces(
138 result_namespace => '+Some::Place::Results',
139 resultset_namespace => '+Another::Place::RSets',
140 );
2a4d9487 141
829517d4 142If you'd like to use multiple namespaces of each type, simply use an arrayref
143of namespaces for that option. In the case that the same result
144(or resultset) class exists in multiple namespaces, the latter entries in
145your list of namespaces will override earlier ones.
2a4d9487 146
829517d4 147 My::Schema->load_namespaces(
148 # My::Schema::Results_C::Foo takes precedence over My::Schema::Results_B::Foo :
149 result_namespace => [ 'Results_A', 'Results_B', 'Results_C' ],
150 resultset_namespace => [ '+Some::Place::RSets', 'RSets' ],
151 );
2a4d9487 152
153=cut
154
829517d4 155# Pre-pends our classname to the given relative classname or
156# class namespace, unless there is a '+' prefix, which will
157# be stripped.
158sub _expand_relative_name {
159 my ($class, $name) = @_;
160 return if !$name;
161 $name = $class . '::' . $name if ! ($name =~ s/^\+//);
162 return $name;
2a4d9487 163}
164
f3405058 165# Finds all modules in the supplied namespace, or if omitted in the
166# namespace of $class. Untaints all findings as they can be assumed
167# to be safe
168sub _findallmod {
169 my $proto = shift;
170 my $ns = shift || ref $proto || $proto;
171
172 my @mods = Module::Find::findallmod($ns);
173
174 # try to untaint module names. mods where this fails
175 # are left alone so we don't have to change the old behavior
176 no locale; # localized \w doesn't untaint expression
177 return map { $_ =~ m/^( (?:\w+::)* \w+ )$/x ? $1 : $_ } @mods;
178}
179
829517d4 180# returns a hash of $shortname => $fullname for every package
b488020e 181# found in the given namespaces ($shortname is with the $fullname's
182# namespace stripped off)
829517d4 183sub _map_namespaces {
184 my ($class, @namespaces) = @_;
6eec9003 185
829517d4 186 my @results_hash;
187 foreach my $namespace (@namespaces) {
188 push(
189 @results_hash,
190 map { (substr($_, length "${namespace}::"), $_) }
f3405058 191 $class->_findallmod($namespace)
829517d4 192 );
0dc79249 193 }
27f01d1f 194
829517d4 195 @results_hash;
ea20d0fd 196}
197
b488020e 198# returns the result_source_instance for the passed class/object,
199# or dies with an informative message (used by load_namespaces)
200sub _ns_get_rsrc_instance {
201 my $class = shift;
202 my $rs = ref ($_[0]) || $_[0];
203
204 if ($rs->can ('result_source_instance') ) {
0647e0cc 205 return $rs->result_source_instance;
b488020e 206 }
207 else {
208 $class->throw_exception (
209 "Attempt to load_namespaces() class $rs failed - are you sure this is a real Result Class?"
210 );
211 }
212}
213
829517d4 214sub load_namespaces {
215 my ($class, %args) = @_;
0dc79249 216
829517d4 217 my $result_namespace = delete $args{result_namespace} || 'Result';
218 my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
219 my $default_resultset_class = delete $args{default_resultset_class};
0dc79249 220
829517d4 221 $class->throw_exception('load_namespaces: unknown option(s): '
222 . join(q{,}, map { qq{'$_'} } keys %args))
223 if scalar keys %args;
0dc79249 224
829517d4 225 $default_resultset_class
226 = $class->_expand_relative_name($default_resultset_class);
9b1ba0f2 227
829517d4 228 for my $arg ($result_namespace, $resultset_namespace) {
229 $arg = [ $arg ] if !ref($arg) && $arg;
9b1ba0f2 230
829517d4 231 $class->throw_exception('load_namespaces: namespace arguments must be '
232 . 'a simple string or an arrayref')
233 if ref($arg) ne 'ARRAY';
9b1ba0f2 234
829517d4 235 $_ = $class->_expand_relative_name($_) for (@$arg);
236 }
ea20d0fd 237
829517d4 238 my %results = $class->_map_namespaces(@$result_namespace);
239 my %resultsets = $class->_map_namespaces(@$resultset_namespace);
27f01d1f 240
829517d4 241 my @to_register;
242 {
87bf71d5 243 no warnings qw/redefine/;
244 local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
245 use warnings qw/redefine/;
27f01d1f 246
3988ce40 247 # ensure classes are loaded and attached in inheritance order
f5ef5fa1 248 for my $res (values %results) {
249 $class->ensure_class_loaded($res);
250 }
3988ce40 251 my %inh_idx;
252 my @subclass_last = sort {
253
254 ($inh_idx{$a} ||=
255 scalar @{mro::get_linear_isa( $results{$a} )}
256 )
257
258 <=>
259
260 ($inh_idx{$b} ||=
261 scalar @{mro::get_linear_isa( $results{$b} )}
262 )
263
264 } keys(%results);
265
3d27f771 266 foreach my $result (@subclass_last) {
829517d4 267 my $result_class = $results{$result};
82b01c38 268
829517d4 269 my $rs_class = delete $resultsets{$result};
b488020e 270 my $rs_set = $class->_ns_get_rsrc_instance ($result_class)->resultset_class;
3988ce40 271
829517d4 272 if($rs_set && $rs_set ne 'DBIx::Class::ResultSet') {
3d27f771 273 if($rs_class && $rs_class ne $rs_set) {
341d5ede 274 carp "We found ResultSet class '$rs_class' for '$result', but it seems "
829517d4 275 . "that you had already set '$result' to use '$rs_set' instead";
276 }
277 }
278 elsif($rs_class ||= $default_resultset_class) {
279 $class->ensure_class_loaded($rs_class);
1d3108a4 280 if(!$rs_class->isa("DBIx::Class::ResultSet")) {
281 carp "load_namespaces found ResultSet class $rs_class that does not subclass DBIx::Class::ResultSet";
282 }
283
b488020e 284 $class->_ns_get_rsrc_instance ($result_class)->resultset_class($rs_class);
829517d4 285 }
82b01c38 286
b488020e 287 my $source_name = $class->_ns_get_rsrc_instance ($result_class)->source_name || $result;
0e6c5d58 288
289 push(@to_register, [ $source_name, $result_class ]);
829517d4 290 }
291 }
ea20d0fd 292
829517d4 293 foreach (sort keys %resultsets) {
341d5ede 294 carp "load_namespaces found ResultSet class $_ with no "
829517d4 295 . 'corresponding Result class';
296 }
ea20d0fd 297
87bf71d5 298 Class::C3->reinitialize if DBIx::Class::_ENV_::OLD_MRO;
299
829517d4 300 $class->register_class(@$_) for (@to_register);
ea20d0fd 301
829517d4 302 return;
ea20d0fd 303}
304
87c4e602 305=head2 load_classes
306
27f01d1f 307=over 4
308
309=item Arguments: @classes?, { $namespace => [ @classes ] }+
310
311=back
076652e8 312
1ab61457 313L</load_classes> is an alternative method to L</load_namespaces>, both of
314which serve similar purposes, each with different advantages and disadvantages.
315In the general case you should use L</load_namespaces>, unless you need to
316be able to specify that only specific classes are loaded at runtime.
829517d4 317
82b01c38 318With no arguments, this method uses L<Module::Find> to find all classes under
319the schema's namespace. Otherwise, this method loads the classes you specify
320(using L<use>), and registers them (using L</"register_class">).
076652e8 321
2053ab2a 322It is possible to comment out classes with a leading C<#>, but note that perl
323will think it's a mistake (trying to use a comment in a qw list), so you'll
324need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 325
829517d4 326If any classes found do not appear to be Result class files, you will
327get the following warning:
328
fd323bf1 329 Failed to load $comp_class. Can't find source_name method. Is
829517d4 330 $comp_class really a full DBIC result class? Fix it, move it elsewhere,
331 or make your load_classes call more specific.
332
2053ab2a 333Example:
82b01c38 334
335 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 336 # etc. (anything under the My::Schema namespace)
82b01c38 337
338 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
339 # not Other::Namespace::LinerNotes nor My::Schema::Track
340 My::Schema->load_classes(qw/ CD Artist #Track /, {
341 Other::Namespace => [qw/ Producer #LinerNotes /],
342 });
343
076652e8 344=cut
345
a02675cd 346sub load_classes {
5ce32fc1 347 my ($class, @params) = @_;
bab77431 348
5ce32fc1 349 my %comps_for;
bab77431 350
5ce32fc1 351 if (@params) {
352 foreach my $param (@params) {
353 if (ref $param eq 'ARRAY') {
354 # filter out commented entries
355 my @modules = grep { $_ !~ /^#/ } @$param;
bab77431 356
5ce32fc1 357 push (@{$comps_for{$class}}, @modules);
358 }
359 elsif (ref $param eq 'HASH') {
360 # more than one namespace possible
361 for my $comp ( keys %$param ) {
362 # filter out commented entries
363 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
364
365 push (@{$comps_for{$comp}}, @modules);
366 }
367 }
368 else {
369 # filter out commented entries
370 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
371 }
372 }
373 } else {
bc0c9800 374 my @comp = map { substr $_, length "${class}::" }
f3405058 375 $class->_findallmod;
5ce32fc1 376 $comps_for{$class} = \@comp;
41a6f8c0 377 }
5ce32fc1 378
e6efde04 379 my @to_register;
380 {
381 no warnings qw/redefine/;
87bf71d5 382 local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
383 use warnings qw/redefine/;
384
e6efde04 385 foreach my $prefix (keys %comps_for) {
386 foreach my $comp (@{$comps_for{$prefix}||[]}) {
387 my $comp_class = "${prefix}::${comp}";
c037c03a 388 $class->ensure_class_loaded($comp_class);
bab77431 389
89271e56 390 my $snsub = $comp_class->can('source_name');
391 if(! $snsub ) {
341d5ede 392 carp "Failed to load $comp_class. Can't find source_name method. Is $comp_class really a full DBIC result class? Fix it, move it elsewhere, or make your load_classes call more specific.";
89271e56 393 next;
394 }
395 $comp = $snsub->($comp_class) || $comp;
396
93405cf0 397 push(@to_register, [ $comp, $comp_class ]);
bfb2bd4f 398 }
5ce32fc1 399 }
a02675cd 400 }
87bf71d5 401 Class::C3->reinitialize if DBIx::Class::_ENV_::OLD_MRO;
e6efde04 402
403 foreach my $to (@to_register) {
404 $class->register_class(@$to);
405 # if $class->can('result_source_instance');
406 }
a02675cd 407}
408
829517d4 409=head2 storage_type
2374c5ff 410
411=over 4
412
829517d4 413=item Arguments: $storage_type|{$storage_type, \%args}
414
415=item Return value: $storage_type|{$storage_type, \%args}
416
417=item Default value: DBIx::Class::Storage::DBI
2374c5ff 418
419=back
420
829517d4 421Set the storage class that will be instantiated when L</connect> is called.
422If the classname starts with C<::>, the prefix C<DBIx::Class::Storage> is
95787afe 423assumed by L</connect>.
2374c5ff 424
829517d4 425You want to use this to set subclasses of L<DBIx::Class::Storage::DBI>
95787afe 426in cases where the appropriate subclass is not autodetected.
85bd0538 427
829517d4 428If your storage type requires instantiation arguments, those are
429defined as a second argument in the form of a hashref and the entire
430value needs to be wrapped into an arrayref or a hashref. We support
431both types of refs here in order to play nice with your
432Config::[class] or your choice. See
433L<DBIx::Class::Storage::DBI::Replicated> for an example of this.
0f4ec1d2 434
829517d4 435=head2 exception_action
f017c022 436
829517d4 437=over 4
0f4ec1d2 438
829517d4 439=item Arguments: $code_reference
f017c022 440
829517d4 441=item Return value: $code_reference
85bd0538 442
829517d4 443=item Default value: None
2374c5ff 444
829517d4 445=back
f017c022 446
c3e9f718 447When L</throw_exception> is invoked and L</exception_action> is set to a code
448reference, this reference will be called instead of
449L<DBIx::Class::Exception/throw>, with the exception message passed as the only
450argument.
f017c022 451
c3e9f718 452Your custom throw code B<must> rethrow the exception, as L</throw_exception> is
453an integral part of DBIC's internal execution control flow.
f017c022 454
829517d4 455Example:
f017c022 456
829517d4 457 package My::Schema;
458 use base qw/DBIx::Class::Schema/;
459 use My::ExceptionClass;
460 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
461 __PACKAGE__->load_classes;
2374c5ff 462
829517d4 463 # or:
464 my $schema_obj = My::Schema->connect( .... );
465 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
0f4ec1d2 466
829517d4 467=head2 stacktrace
f017c022 468
829517d4 469=over 4
2374c5ff 470
829517d4 471=item Arguments: boolean
2374c5ff 472
829517d4 473=back
2374c5ff 474
829517d4 475Whether L</throw_exception> should include stack trace information.
476Defaults to false normally, but defaults to true if C<$ENV{DBIC_TRACE}>
477is true.
0f4ec1d2 478
829517d4 479=head2 sqlt_deploy_hook
0f4ec1d2 480
829517d4 481=over
0f4ec1d2 482
829517d4 483=item Arguments: $sqlt_schema
2374c5ff 484
829517d4 485=back
2374c5ff 486
fd323bf1 487An optional sub which you can declare in your own Schema class that will get
829517d4 488passed the L<SQL::Translator::Schema> object when you deploy the schema via
489L</create_ddl_dir> or L</deploy>.
0f4ec1d2 490
fd323bf1 491For an example of what you can do with this, see
829517d4 492L<DBIx::Class::Manual::Cookbook/Adding Indexes And Functions To Your SQL>.
fdcd8145 493
2d7d8459 494Note that sqlt_deploy_hook is called by L</deployment_statements>, which in turn
495is called before L</deploy>. Therefore the hook can be used only to manipulate
496the L<SQL::Translator::Schema> object before it is turned into SQL fed to the
497database. If you want to execute post-deploy statements which can not be generated
498by L<SQL::Translator>, the currently suggested method is to overload L</deploy>
499and use L<dbh_do|DBIx::Class::Storage::DBI/dbh_do>.
500
829517d4 501=head1 METHODS
2374c5ff 502
829517d4 503=head2 connect
87c4e602 504
27f01d1f 505=over 4
506
829517d4 507=item Arguments: @connectinfo
429bd4f1 508
d601dc88 509=item Return Value: $new_schema
27f01d1f 510
511=back
076652e8 512
829517d4 513Creates and returns a new Schema object. The connection info set on it
514is used to create a new instance of the storage backend and set it on
515the Schema object.
1c133e22 516
829517d4 517See L<DBIx::Class::Storage::DBI/"connect_info"> for DBI-specific
5d52945a 518syntax on the C<@connectinfo> argument, or L<DBIx::Class::Storage> in
829517d4 519general.
1c133e22 520
5d52945a 521Note that C<connect_info> expects an arrayref of arguments, but
faaba25f 522C<connect> does not. C<connect> wraps its arguments in an arrayref
5d52945a 523before passing them to C<connect_info>.
524
4c7d99ca 525=head3 Overloading
526
527C<connect> is a convenience method. It is equivalent to calling
528$schema->clone->connection(@connectinfo). To write your own overloaded
529version, overload L</connection> instead.
530
076652e8 531=cut
532
829517d4 533sub connect { shift->clone->connection(@_) }
e678398e 534
829517d4 535=head2 resultset
77254782 536
27f01d1f 537=over 4
538
829517d4 539=item Arguments: $source_name
82b01c38 540
829517d4 541=item Return Value: $resultset
27f01d1f 542
543=back
13765dad 544
829517d4 545 my $rs = $schema->resultset('DVD');
82b01c38 546
829517d4 547Returns the L<DBIx::Class::ResultSet> object for the registered source
548name.
77254782 549
550=cut
551
829517d4 552sub resultset {
553 my ($self, $moniker) = @_;
73d47f9f 554 $self->throw_exception('resultset() expects a source name')
555 unless defined $moniker;
829517d4 556 return $self->source($moniker)->resultset;
b7951443 557}
558
829517d4 559=head2 sources
6b43ba5f 560
561=over 4
562
829517d4 563=item Return Value: @source_names
6b43ba5f 564
565=back
566
829517d4 567 my @source_names = $schema->sources;
6b43ba5f 568
829517d4 569Lists names of all the sources registered on this Schema object.
6b43ba5f 570
829517d4 571=cut
161fb223 572
829517d4 573sub sources { return keys %{shift->source_registrations}; }
106d5f3b 574
829517d4 575=head2 source
87c4e602 576
27f01d1f 577=over 4
578
829517d4 579=item Arguments: $source_name
66d9ef6b 580
829517d4 581=item Return Value: $result_source
27f01d1f 582
583=back
82b01c38 584
829517d4 585 my $source = $schema->source('Book');
85f78622 586
829517d4 587Returns the L<DBIx::Class::ResultSource> object for the registered
588source name.
66d9ef6b 589
590=cut
591
829517d4 592sub source {
f5f2af8f 593 my $self = shift;
594
595 $self->throw_exception("source() expects a source name")
596 unless @_;
597
598 my $moniker = shift;
599
829517d4 600 my $sreg = $self->source_registrations;
601 return $sreg->{$moniker} if exists $sreg->{$moniker};
602
603 # if we got here, they probably passed a full class name
604 my $mapped = $self->class_mappings->{$moniker};
605 $self->throw_exception("Can't find source for ${moniker}")
606 unless $mapped && exists $sreg->{$mapped};
607 return $sreg->{$mapped};
161fb223 608}
609
829517d4 610=head2 class
87c4e602 611
27f01d1f 612=over 4
613
829517d4 614=item Arguments: $source_name
66d9ef6b 615
829517d4 616=item Return Value: $classname
27f01d1f 617
618=back
82b01c38 619
829517d4 620 my $class = $schema->class('CD');
621
622Retrieves the Result class name for the given source name.
66d9ef6b 623
624=cut
625
829517d4 626sub class {
627 my ($self, $moniker) = @_;
628 return $self->source($moniker)->result_class;
629}
08b515f1 630
4012acd8 631=head2 txn_do
08b515f1 632
4012acd8 633=over 4
08b515f1 634
4012acd8 635=item Arguments: C<$coderef>, @coderef_args?
08b515f1 636
4012acd8 637=item Return Value: The return value of $coderef
08b515f1 638
4012acd8 639=back
08b515f1 640
4012acd8 641Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
642returning its result (if any). Equivalent to calling $schema->storage->txn_do.
643See L<DBIx::Class::Storage/"txn_do"> for more information.
08b515f1 644
4012acd8 645This interface is preferred over using the individual methods L</txn_begin>,
646L</txn_commit>, and L</txn_rollback> below.
08b515f1 647
f9f06ae0 648WARNING: If you are connected with C<< AutoCommit => 0 >> the transaction is
281719d2 649considered nested, and you will still need to call L</txn_commit> to write your
f9f06ae0 650changes when appropriate. You will also want to connect with C<< auto_savepoint =>
6511 >> to get partial rollback to work, if the storage driver for your database
281719d2 652supports it.
653
f9f06ae0 654Connecting with C<< AutoCommit => 1 >> is recommended.
281719d2 655
4012acd8 656=cut
08b515f1 657
4012acd8 658sub txn_do {
659 my $self = shift;
08b515f1 660
4012acd8 661 $self->storage or $self->throw_exception
662 ('txn_do called on $schema without storage');
08b515f1 663
4012acd8 664 $self->storage->txn_do(@_);
665}
66d9ef6b 666
6936e902 667=head2 txn_scope_guard
75c8a7ab 668
fd323bf1 669Runs C<txn_scope_guard> on the schema's storage. See
89028f42 670L<DBIx::Class::Storage/txn_scope_guard>.
75c8a7ab 671
b85be4c1 672=cut
673
1bc193ac 674sub txn_scope_guard {
675 my $self = shift;
676
677 $self->storage or $self->throw_exception
678 ('txn_scope_guard called on $schema without storage');
679
680 $self->storage->txn_scope_guard(@_);
681}
682
4012acd8 683=head2 txn_begin
a62cf8d4 684
4012acd8 685Begins a transaction (does nothing if AutoCommit is off). Equivalent to
686calling $schema->storage->txn_begin. See
8bfce9d5 687L<DBIx::Class::Storage/"txn_begin"> for more information.
27f01d1f 688
4012acd8 689=cut
82b01c38 690
4012acd8 691sub txn_begin {
692 my $self = shift;
27f01d1f 693
4012acd8 694 $self->storage or $self->throw_exception
695 ('txn_begin called on $schema without storage');
a62cf8d4 696
4012acd8 697 $self->storage->txn_begin;
698}
a62cf8d4 699
4012acd8 700=head2 txn_commit
a62cf8d4 701
4012acd8 702Commits the current transaction. Equivalent to calling
8bfce9d5 703$schema->storage->txn_commit. See L<DBIx::Class::Storage/"txn_commit">
4012acd8 704for more information.
a62cf8d4 705
4012acd8 706=cut
a62cf8d4 707
4012acd8 708sub txn_commit {
709 my $self = shift;
a62cf8d4 710
4012acd8 711 $self->storage or $self->throw_exception
712 ('txn_commit called on $schema without storage');
a62cf8d4 713
4012acd8 714 $self->storage->txn_commit;
715}
70634260 716
4012acd8 717=head2 txn_rollback
a62cf8d4 718
4012acd8 719Rolls back the current transaction. Equivalent to calling
720$schema->storage->txn_rollback. See
8bfce9d5 721L<DBIx::Class::Storage/"txn_rollback"> for more information.
a62cf8d4 722
723=cut
724
4012acd8 725sub txn_rollback {
726 my $self = shift;
a62cf8d4 727
19630353 728 $self->storage or $self->throw_exception
4012acd8 729 ('txn_rollback called on $schema without storage');
a62cf8d4 730
4012acd8 731 $self->storage->txn_rollback;
a62cf8d4 732}
733
829517d4 734=head2 storage
66d9ef6b 735
829517d4 736 my $storage = $schema->storage;
04786a4c 737
829517d4 738Returns the L<DBIx::Class::Storage> object for this Schema. Grab this
739if you want to turn on SQL statement debugging at runtime, or set the
740quote character. For the default storage, the documentation can be
741found in L<DBIx::Class::Storage::DBI>.
66d9ef6b 742
87c4e602 743=head2 populate
744
27f01d1f 745=over 4
746
16c5f7d3 747=item Arguments: $source_name, \@data;
27f01d1f 748
829517d4 749=item Return value: \@$objects | nothing
750
27f01d1f 751=back
a37a4697 752
16c5f7d3 753Pass this method a resultsource name, and an arrayref of
754arrayrefs. The arrayrefs should contain a list of column names,
fd323bf1 755followed by one or many sets of matching data for the given columns.
16c5f7d3 756
744076d8 757In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
758to insert the data, as this is a fast method. However, insert_bulk currently
759assumes that your datasets all contain the same type of values, using scalar
760references in a column in one row, and not in another will probably not work.
761
762Otherwise, each set of data is inserted into the database using
16c5f7d3 763L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
764objects is returned.
82b01c38 765
48580715 766e.g.
a37a4697 767
24d67825 768 $schema->populate('Artist', [
769 [ qw/artistid name/ ],
770 [ 1, 'Popular Band' ],
771 [ 2, 'Indie Band' ],
a62cf8d4 772 ...
773 ]);
d4daee7b 774
fd323bf1 775Since wantarray context is basically the same as looping over $rs->create(...)
5a93e138 776you won't see any performance benefits and in this case the method is more for
777convenience. Void context sends the column information directly to storage
fd323bf1 778using <DBI>s bulk insert method. So the performance will be much better for
5a93e138 779storages that support this method.
780
fd323bf1 781Because of this difference in the way void context inserts rows into your
5a93e138 782database you need to note how this will effect any loaded components that
fd323bf1 783override or augment insert. For example if you are using a component such
784as L<DBIx::Class::UUIDColumns> to populate your primary keys you MUST use
5a93e138 785wantarray context if you want the PKs automatically created.
a37a4697 786
787=cut
788
789sub populate {
790 my ($self, $name, $data) = @_;
c4e67d31 791 if(my $rs = $self->resultset($name)) {
792 if(defined wantarray) {
793 return $rs->populate($data);
794 } else {
795 $rs->populate($data);
54e0bd06 796 }
c4e67d31 797 } else {
fd323bf1 798 $self->throw_exception("$name is not a resultset");
8b93a938 799 }
a37a4697 800}
801
829517d4 802=head2 connection
803
804=over 4
805
806=item Arguments: @args
807
808=item Return Value: $new_schema
809
810=back
811
812Similar to L</connect> except sets the storage object and connection
813data in-place on the Schema class. You should probably be calling
814L</connect> to get a proper Schema object instead.
815
4c7d99ca 816=head3 Overloading
817
818Overload C<connection> to change the behaviour of C<connect>.
829517d4 819
820=cut
821
822sub connection {
823 my ($self, @info) = @_;
824 return $self if !@info && $self->storage;
d4daee7b 825
fd323bf1 826 my ($storage_class, $args) = ref $self->storage_type ?
829517d4 827 ($self->_normalize_storage_type($self->storage_type),{}) : ($self->storage_type, {});
d4daee7b 828
829517d4 829 $storage_class = 'DBIx::Class::Storage'.$storage_class
830 if $storage_class =~ m/^::/;
9780718f 831 try {
832 $self->ensure_class_loaded ($storage_class);
833 }
834 catch {
835 $self->throw_exception(
836 "No arguments to load_classes and couldn't load ${storage_class} ($_)"
837 );
838 };
829517d4 839 my $storage = $storage_class->new($self=>$args);
840 $storage->connect_info(\@info);
841 $self->storage($storage);
842 return $self;
843}
844
845sub _normalize_storage_type {
846 my ($self, $storage_type) = @_;
847 if(ref $storage_type eq 'ARRAY') {
848 return @$storage_type;
849 } elsif(ref $storage_type eq 'HASH') {
850 return %$storage_type;
851 } else {
852 $self->throw_exception('Unsupported REFTYPE given: '. ref $storage_type);
853 }
854}
855
856=head2 compose_namespace
82cc0386 857
858=over 4
859
829517d4 860=item Arguments: $target_namespace, $additional_base_class?
861
862=item Retur Value: $new_schema
863
864=back
865
866For each L<DBIx::Class::ResultSource> in the schema, this method creates a
867class in the target namespace (e.g. $target_namespace::CD,
868$target_namespace::Artist) that inherits from the corresponding classes
869attached to the current schema.
870
871It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
872new $schema object. If C<$additional_base_class> is given, the new composed
48580715 873classes will inherit from first the corresponding class from the current
829517d4 874schema then the base class.
875
876For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
877
878 $schema->compose_namespace('My::DB', 'Base::Class');
879 print join (', ', @My::DB::CD::ISA) . "\n";
880 print join (', ', @My::DB::Artist::ISA) ."\n";
881
882will produce the output
883
884 My::Schema::CD, Base::Class
885 My::Schema::Artist, Base::Class
886
887=cut
888
889# this might be oversimplified
890# sub compose_namespace {
891# my ($self, $target, $base) = @_;
892
893# my $schema = $self->clone;
894# foreach my $moniker ($schema->sources) {
895# my $source = $schema->source($moniker);
896# my $target_class = "${target}::${moniker}";
897# $self->inject_base(
898# $target_class => $source->result_class, ($base ? $base : ())
899# );
900# $source->result_class($target_class);
901# $target_class->result_source_instance($source)
902# if $target_class->can('result_source_instance');
903# $schema->register_source($moniker, $source);
904# }
905# return $schema;
906# }
907
908sub compose_namespace {
909 my ($self, $target, $base) = @_;
910 my $schema = $self->clone;
911 {
912 no warnings qw/redefine/;
87bf71d5 913 local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
914 use warnings qw/redefine/;
915
a8c2c746 916 no strict qw/refs/;
829517d4 917 foreach my $moniker ($schema->sources) {
918 my $source = $schema->source($moniker);
919 my $target_class = "${target}::${moniker}";
920 $self->inject_base(
921 $target_class => $source->result_class, ($base ? $base : ())
922 );
923 $source->result_class($target_class);
a8c2c746 924 if ($target_class->can('result_source_instance')) {
925
926 # since the newly created classes are registered only with
927 # the instance of $schema, it should be safe to weaken
928 # the ref (it will GC when $schema is destroyed)
929 $target_class->result_source_instance($source);
930 weaken ${"${target_class}::__cag_result_source_instance"};
931 }
829517d4 932 $schema->register_source($moniker, $source);
933 }
934 }
87bf71d5 935 Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
829517d4 936 {
937 no strict 'refs';
938 no warnings 'redefine';
939 foreach my $meth (qw/class source resultset/) {
6298a324 940 *{"${target}::${meth}"} = subname "${target}::${meth}" =>
829517d4 941 sub { shift->schema->$meth(@_) };
942 }
943 }
944 return $schema;
945}
946
947sub setup_connection_class {
948 my ($class, $target, @info) = @_;
949 $class->inject_base($target => 'DBIx::Class::DB');
950 #$target->load_components('DB');
951 $target->connection(@info);
952}
953
954=head2 svp_begin
955
fd323bf1 956Creates a new savepoint (does nothing outside a transaction).
829517d4 957Equivalent to calling $schema->storage->svp_begin. See
8bfce9d5 958L<DBIx::Class::Storage/"svp_begin"> for more information.
829517d4 959
960=cut
961
962sub svp_begin {
963 my ($self, $name) = @_;
964
965 $self->storage or $self->throw_exception
966 ('svp_begin called on $schema without storage');
967
968 $self->storage->svp_begin($name);
969}
970
971=head2 svp_release
972
fd323bf1 973Releases a savepoint (does nothing outside a transaction).
829517d4 974Equivalent to calling $schema->storage->svp_release. See
8bfce9d5 975L<DBIx::Class::Storage/"svp_release"> for more information.
829517d4 976
977=cut
978
979sub svp_release {
980 my ($self, $name) = @_;
981
982 $self->storage or $self->throw_exception
983 ('svp_release called on $schema without storage');
82cc0386 984
829517d4 985 $self->storage->svp_release($name);
986}
82cc0386 987
829517d4 988=head2 svp_rollback
db5dc233 989
fd323bf1 990Rollback to a savepoint (does nothing outside a transaction).
829517d4 991Equivalent to calling $schema->storage->svp_rollback. See
8bfce9d5 992L<DBIx::Class::Storage/"svp_rollback"> for more information.
82cc0386 993
829517d4 994=cut
82cc0386 995
829517d4 996sub svp_rollback {
997 my ($self, $name) = @_;
82cc0386 998
829517d4 999 $self->storage or $self->throw_exception
1000 ('svp_rollback called on $schema without storage');
82cc0386 1001
829517d4 1002 $self->storage->svp_rollback($name);
1003}
db5dc233 1004
829517d4 1005=head2 clone
613397e7 1006
84c5863b 1007=over 4
613397e7 1008
829517d4 1009=item Return Value: $new_schema
613397e7 1010
1011=back
1012
829517d4 1013Clones the schema and its associated result_source objects and returns the
1014copy.
1015
1016=cut
1017
1018sub clone {
1019 my ($self) = @_;
1020 my $clone = { (ref $self ? %$self : ()) };
1021 bless $clone, (ref $self || $self);
1022
1023 $clone->class_mappings({ %{$clone->class_mappings} });
1024 $clone->source_registrations({ %{$clone->source_registrations} });
1025 foreach my $moniker ($self->sources) {
1026 my $source = $self->source($moniker);
1027 my $new = $source->new($source);
1028 # we use extra here as we want to leave the class_mappings as they are
1029 # but overwrite the source_registrations entry with the new source
1030 $clone->register_extra_source($moniker => $new);
1031 }
1032 $clone->storage->set_schema($clone) if $clone->storage;
1033 return $clone;
1034}
613397e7 1035
5160b401 1036=head2 throw_exception
701da8c4 1037
75d07914 1038=over 4
82b01c38 1039
ebc77b53 1040=item Arguments: $message
82b01c38 1041
1042=back
1043
1044Throws an exception. Defaults to using L<Carp::Clan> to report errors from
db5dc233 1045user's perspective. See L</exception_action> for details on overriding
4b946902 1046this method's behavior. If L</stacktrace> is turned on, C<throw_exception>'s
1047default behavior will provide a detailed stack trace.
701da8c4 1048
1049=cut
1050
c3e9f718 1051my $false_exception_action_warned;
701da8c4 1052sub throw_exception {
82cc0386 1053 my $self = shift;
4981dc70 1054
c3e9f718 1055 if (my $act = $self->exception_action) {
1056 if ($act->(@_)) {
1057 DBIx::Class::Exception->throw(
1058 "Invocation of the exception_action handler installed on $self did *not*"
1059 .' result in an exception. DBIx::Class is unable to function without a reliable'
1060 .' exception mechanism, ensure that exception_action does not hide exceptions'
1061 ." (original error: $_[0])"
1062 );
1063 }
1064 elsif(! $false_exception_action_warned++) {
1065 carp (
1066 "The exception_action handler installed on $self returned false instead"
1067 .' of throwing an exception. This behavior has been deprecated, adjust your'
1068 .' handler to always rethrow the supplied error.'
1069 );
1070 }
1071 }
1072
1073 DBIx::Class::Exception->throw($_[0], $self->stacktrace);
701da8c4 1074}
1075
dfccde48 1076=head2 deploy
1c339d71 1077
82b01c38 1078=over 4
1079
10976519 1080=item Arguments: \%sqlt_args, $dir
82b01c38 1081
1082=back
1083
1084Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 1085
10976519 1086See L<SQL::Translator/METHODS> for a list of values for C<\%sqlt_args>.
1087The most common value for this would be C<< { add_drop_table => 1 } >>
1088to have the SQL produced include a C<DROP TABLE> statement for each table
1089created. For quoting purposes supply C<quote_table_names> and
3e82fc27 1090C<quote_field_names>.
51bace1c 1091
fd323bf1 1092Additionally, the DBIx::Class parser accepts a C<sources> parameter as a hash
1093ref or an array ref, containing a list of source to deploy. If present, then
0e2c6809 1094only the sources listed will get deployed. Furthermore, you can use the
1095C<add_fk_index> parser parameter to prevent the parser from creating an index for each
1096FK.
499adf63 1097
1c339d71 1098=cut
1099
1100sub deploy {
6e73ac25 1101 my ($self, $sqltargs, $dir) = @_;
1c339d71 1102 $self->throw_exception("Can't deploy without storage") unless $self->storage;
6e73ac25 1103 $self->storage->deploy($self, undef, $sqltargs, $dir);
1c339d71 1104}
1105
0e0ce6c1 1106=head2 deployment_statements
1107
1108=over 4
1109
10976519 1110=item Arguments: See L<DBIx::Class::Storage::DBI/deployment_statements>
0e0ce6c1 1111
829517d4 1112=item Return value: $listofstatements
1113
0e0ce6c1 1114=back
1115
10976519 1116A convenient shortcut to
1117C<< $self->storage->deployment_statements($self, @args) >>.
1118Returns the SQL statements used by L</deploy> and
1119L<DBIx::Class::Schema::Storage/deploy>.
0e0ce6c1 1120
1121=cut
1122
1123sub deployment_statements {
7ad93f5a 1124 my $self = shift;
0e0ce6c1 1125
1126 $self->throw_exception("Can't generate deployment statements without a storage")
1127 if not $self->storage;
1128
7ad93f5a 1129 $self->storage->deployment_statements($self, @_);
0e0ce6c1 1130}
1131
6dfbe2f8 1132=head2 create_ddl_dir
c0f61310 1133
1134=over 4
1135
10976519 1136=item Arguments: See L<DBIx::Class::Storage::DBI/create_ddl_dir>
c0f61310 1137
1138=back
1139
fd323bf1 1140A convenient shortcut to
10976519 1141C<< $self->storage->create_ddl_dir($self, @args) >>.
c9d2e0a2 1142
10976519 1143Creates an SQL file based on the Schema, for each of the specified
1144database types, in the given directory.
c9d2e0a2 1145
c0f61310 1146=cut
1147
6e73ac25 1148sub create_ddl_dir {
e673f011 1149 my $self = shift;
1150
1151 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
1152 $self->storage->create_ddl_dir($self, @_);
1153}
1154
e63a82f7 1155=head2 ddl_filename
9b83fccd 1156
c9d2e0a2 1157=over 4
1158
99a74c4a 1159=item Arguments: $database-type, $version, $directory, $preversion
c9d2e0a2 1160
829517d4 1161=item Return value: $normalised_filename
1162
c9d2e0a2 1163=back
1164
99a74c4a 1165 my $filename = $table->ddl_filename($type, $version, $dir, $preversion)
c9d2e0a2 1166
1167This method is called by C<create_ddl_dir> to compose a file name out of
1168the supplied directory, database type and version number. The default file
1169name format is: C<$dir$schema-$version-$type.sql>.
9b83fccd 1170
c9d2e0a2 1171You may override this method in your schema if you wish to use a different
1172format.
9b83fccd 1173
1acfef8e 1174 WARNING
1175
1176 Prior to DBIx::Class version 0.08100 this method had a different signature:
1177
1178 my $filename = $table->ddl_filename($type, $dir, $version, $preversion)
1179
1180 In recent versions variables $dir and $version were reversed in order to
fd323bf1 1181 bring the signature in line with other Schema/Storage methods. If you
1acfef8e 1182 really need to maintain backward compatibility, you can do the following
1183 in any overriding methods:
1184
1185 ($dir, $version) = ($version, $dir) if ($DBIx::Class::VERSION < 0.08100);
1186
9b83fccd 1187=cut
1188
6e73ac25 1189sub ddl_filename {
99a74c4a 1190 my ($self, $type, $version, $dir, $preversion) = @_;
e673f011 1191
99a74c4a 1192 my $filename = ref($self);
1193 $filename =~ s/::/-/g;
1194 $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql");
1195 $filename =~ s/$version/$preversion-$version/ if($preversion);
d4daee7b 1196
99a74c4a 1197 return $filename;
e673f011 1198}
1199
4146e3da 1200=head2 thaw
1201
fd323bf1 1202Provided as the recommended way of thawing schema objects. You can call
4146e3da 1203C<Storable::thaw> directly if you wish, but the thawed objects will not have a
48580715 1204reference to any schema, so are rather useless.
4146e3da 1205
1206=cut
1207
1208sub thaw {
1209 my ($self, $obj) = @_;
1210 local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1211 return Storable::thaw($obj);
1212}
1213
1214=head2 freeze
1215
26148d36 1216This doesn't actually do anything more than call L<Storable/nfreeze>, it is just
48580715 1217provided here for symmetry.
4146e3da 1218
d2f3e87b 1219=cut
1220
4146e3da 1221sub freeze {
26148d36 1222 return Storable::nfreeze($_[1]);
4146e3da 1223}
1224
1225=head2 dclone
1226
1477a478 1227=over 4
1228
1229=item Arguments: $object
1230
1231=item Return Value: dcloned $object
1232
1233=back
1234
9e9ecfda 1235Recommended way of dcloning L<DBIx::Class::Row> and L<DBIx::Class::ResultSet>
1236objects so their references to the schema object
1237(which itself is B<not> cloned) are properly maintained.
4146e3da 1238
1239=cut
1240
1241sub dclone {
1242 my ($self, $obj) = @_;
1243 local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1244 return Storable::dclone($obj);
1245}
1246
93e4d41a 1247=head2 schema_version
1248
829517d4 1249Returns the current schema class' $VERSION in a normalised way.
93e4d41a 1250
1251=cut
1252
1253sub schema_version {
1254 my ($self) = @_;
1255 my $class = ref($self)||$self;
1256
1257 # does -not- use $schema->VERSION
1258 # since that varies in results depending on if version.pm is installed, and if
1259 # so the perl or XS versions. If you want this to change, bug the version.pm
1260 # author to make vpp and vxs behave the same.
1261
1262 my $version;
1263 {
1264 no strict 'refs';
1265 $version = ${"${class}::VERSION"};
1266 }
1267 return $version;
1268}
1269
829517d4 1270
1271=head2 register_class
1272
1273=over 4
1274
1275=item Arguments: $moniker, $component_class
1276
1277=back
1278
fd323bf1 1279This method is called by L</load_namespaces> and L</load_classes> to install the found classes into your Schema. You should be using those instead of this one.
829517d4 1280
1281You will only need this method if you have your Result classes in
1282files which are not named after the packages (or all in the same
1283file). You may also need it to register classes at runtime.
1284
1285Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
1286calling:
1287
1288 $schema->register_source($moniker, $component_class->result_source_instance);
1289
1290=cut
1291
1292sub register_class {
1293 my ($self, $moniker, $to_register) = @_;
1e36ef62 1294 $self->register_source($moniker => $to_register->result_source_instance);
829517d4 1295}
1296
1297=head2 register_source
1298
1299=over 4
1300
1301=item Arguments: $moniker, $result_source
1302
1303=back
1304
1305This method is called by L</register_class>.
1306
1307Registers the L<DBIx::Class::ResultSource> in the schema with the given
1308moniker.
1309
1310=cut
1311
1312sub register_source {
1313 my $self = shift;
1314
1315 $self->_register_source(@_);
1316}
1317
98cabed3 1318=head2 unregister_source
1319
1320=over 4
1321
1322=item Arguments: $moniker
1323
1324=back
1325
1326Removes the L<DBIx::Class::ResultSource> from the schema for the given moniker.
1327
1328=cut
1329
1330sub unregister_source {
1331 my $self = shift;
1332
1333 $self->_unregister_source(@_);
1334}
1335
829517d4 1336=head2 register_extra_source
1337
1338=over 4
1339
1340=item Arguments: $moniker, $result_source
1341
1342=back
1343
fd323bf1 1344As L</register_source> but should be used if the result class already
829517d4 1345has a source and you want to register an extra one.
1346
1347=cut
1348
1349sub register_extra_source {
1350 my $self = shift;
1351
1352 $self->_register_source(@_, { extra => 1 });
1353}
1354
1355sub _register_source {
1356 my ($self, $moniker, $source, $params) = @_;
1357
6d4f9d94 1358 my $orig_source = $source;
2461ae19 1359
0e6c5d58 1360 $source = $source->new({ %$source, source_name => $moniker });
2461ae19 1361 $source->schema($self);
6298a324 1362 weaken $source->{schema} if ref($self);
2461ae19 1363
1364 my $rs_class = $source->result_class;
829517d4 1365
1366 my %reg = %{$self->source_registrations};
1367 $reg{$moniker} = $source;
1368 $self->source_registrations(\%reg);
1369
829517d4 1370 return if ($params->{extra});
5dfe40b8 1371 return unless defined($rs_class) && $rs_class->can('result_source_instance');
829517d4 1372
2461ae19 1373 my %map = %{$self->class_mappings};
f18d2d04 1374 if (
1375 exists $map{$rs_class}
1376 and
1377 $map{$rs_class} ne $moniker
1378 and
1379 $rs_class->result_source_instance ne $orig_source
1380 ) {
2461ae19 1381 carp "$rs_class already has a source, use register_extra_source for additional sources";
829517d4 1382 }
2461ae19 1383 $map{$rs_class} = $moniker;
1384 $self->class_mappings(\%map);
829517d4 1385}
1386
50261284 1387{
1388 my $global_phase_destroy;
1389
66917da3 1390 # SpeedyCGI runs END blocks every cycle but keeps object instances
1391 # hence we have to disable the globaldestroy hatch, and rely on the
1392 # eval trap below (which appears to work, but is risky done so late)
1393 END { $global_phase_destroy = 1 unless $CGI::SpeedyCGI::i_am_speedy }
50261284 1394
1395 sub DESTROY {
1396 return if $global_phase_destroy;
1397
1398 my $self = shift;
1399 my $srcs = $self->source_registrations;
1400
1401 for my $moniker (keys %$srcs) {
1402 # find first source that is not about to be GCed (someone other than $self
1403 # holds a reference to it) and reattach to it, weakening our own link
66917da3 1404 #
1405 # during global destruction (if we have not yet bailed out) this will throw
1406 # which will serve as a signal to not try doing anything else
50261284 1407 if (ref $srcs->{$moniker} and svref_2object($srcs->{$moniker})->REFCNT > 1) {
66917da3 1408 local $@;
1409 eval {
1410 $srcs->{$moniker}->schema($self);
1411 1;
1412 } or do {
1413 $global_phase_destroy = 1;
1414 last;
1415 };
1416
50261284 1417 weaken $srcs->{$moniker};
1418 last;
1419 }
1420 }
1421 }
1422}
1423
829517d4 1424sub _unregister_source {
1425 my ($self, $moniker) = @_;
fd323bf1 1426 my %reg = %{$self->source_registrations};
829517d4 1427
1428 my $source = delete $reg{$moniker};
1429 $self->source_registrations(\%reg);
1430 if ($source->result_class) {
1431 my %map = %{$self->class_mappings};
1432 delete $map{$source->result_class};
1433 $self->class_mappings(\%map);
1434 }
1435}
1436
1437
1438=head2 compose_connection (DEPRECATED)
1439
1440=over 4
1441
1442=item Arguments: $target_namespace, @db_info
1443
1444=item Return Value: $new_schema
1445
1446=back
1447
1448DEPRECATED. You probably wanted compose_namespace.
1449
1450Actually, you probably just wanted to call connect.
1451
1452=begin hidden
1453
1454(hidden due to deprecation)
1455
1456Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
1457calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
1458then injects the L<DBix::Class::ResultSetProxy> component and a
1459resultset_instance classdata entry on all the new classes, in order to support
1460$target_namespaces::$class->search(...) method calls.
1461
1462This is primarily useful when you have a specific need for class method access
1463to a connection. In normal usage it is preferred to call
1464L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
1465on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
1466more information.
1467
1468=end hidden
1469
1470=cut
1471
1472{
1473 my $warn;
1474
1475 sub compose_connection {
1476 my ($self, $target, @info) = @_;
1477
341d5ede 1478 carp "compose_connection deprecated as of 0.08000"
829517d4 1479 unless ($INC{"DBIx/Class/CDBICompat.pm"} || $warn++);
1480
1481 my $base = 'DBIx::Class::ResultSetProxy';
9780718f 1482 try {
1483 eval "require ${base};"
1484 }
1485 catch {
1486 $self->throw_exception
1487 ("No arguments to load_classes and couldn't load ${base} ($_)")
1488 };
d4daee7b 1489
829517d4 1490 if ($self eq $target) {
1491 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
1492 foreach my $moniker ($self->sources) {
1493 my $source = $self->source($moniker);
1494 my $class = $source->result_class;
1495 $self->inject_base($class, $base);
1496 $class->mk_classdata(resultset_instance => $source->resultset);
1497 $class->mk_classdata(class_resolver => $self);
1498 }
1499 $self->connection(@info);
1500 return $self;
1501 }
d4daee7b 1502
829517d4 1503 my $schema = $self->compose_namespace($target, $base);
1504 {
1505 no strict 'refs';
1506 my $name = join '::', $target, 'schema';
6298a324 1507 *$name = subname $name, sub { $schema };
829517d4 1508 }
d4daee7b 1509
829517d4 1510 $schema->connection(@info);
1511 foreach my $moniker ($schema->sources) {
1512 my $source = $schema->source($moniker);
1513 my $class = $source->result_class;
1514 #warn "$moniker $class $source ".$source->storage;
1515 $class->mk_classdata(result_source_instance => $source);
1516 $class->mk_classdata(resultset_instance => $source->resultset);
1517 $class->mk_classdata(class_resolver => $schema);
1518 }
1519 return $schema;
1520 }
1521}
1522
a02675cd 15231;
c2da098a 1524
c2da098a 1525=head1 AUTHORS
1526
daec44b8 1527Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 1528
1529=head1 LICENSE
1530
1531You may distribute this code under the same terms as Perl itself.
1532
1533=cut