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