revert part of 3220, apparently it is breaking cloning behavior in subtle ways that...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema.pm
1 package DBIx::Class::Schema;
2
3 use strict;
4 use warnings;
5
6 use Carp::Clan qw/^DBIx::Class/;
7 use Scalar::Util qw/weaken/;
8
9 use base qw/DBIx::Class/;
10
11 __PACKAGE__->mk_classdata('class_mappings' => {});
12 __PACKAGE__->mk_classdata('source_registrations' => {});
13 __PACKAGE__->mk_classdata('storage_type' => '::DBI');
14 __PACKAGE__->mk_classdata('storage');
15
16 =head1 NAME
17
18 DBIx::Class::Schema - composable schemas
19
20 =head1 SYNOPSIS
21
22   package Library::Schema;
23   use base qw/DBIx::Class::Schema/;
24
25   # load Library::Schema::CD, Library::Schema::Book, Library::Schema::DVD
26   __PACKAGE__->load_classes(qw/CD Book DVD/);
27
28   package Library::Schema::CD;
29   use base qw/DBIx::Class/;
30   __PACKAGE__->load_components(qw/PK::Auto Core/); # for example
31   __PACKAGE__->table('cd');
32
33   # Elsewhere in your code:
34   my $schema1 = Library::Schema->connect(
35     $dsn,
36     $user,
37     $password,
38     { AutoCommit => 0 },
39   );
40
41   my $schema2 = Library::Schema->connect($coderef_returning_dbh);
42
43   # fetch objects using Library::Schema::DVD
44   my $resultset = $schema1->resultset('DVD')->search( ... );
45   my @dvd_objects = $schema2->resultset('DVD')->search( ... );
46
47 =head1 DESCRIPTION
48
49 Creates database classes based on a schema. This is the recommended way to
50 use L<DBIx::Class> and allows you to use more than one concurrent connection
51 with your classes.
52
53 NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
54 carefully, as DBIx::Class does things a little differently. Note in
55 particular which module inherits off which.
56
57 =head1 METHODS
58
59 =head2 register_class
60
61 =over 4
62
63 =item Arguments: $moniker, $component_class
64
65 =back
66
67 Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
68 calling:
69
70   $schema->register_source($moniker, $component_class->result_source_instance);
71
72 =cut
73
74 sub register_class {
75   my ($self, $moniker, $to_register) = @_;
76   $self->register_source($moniker => $to_register->result_source_instance);
77 }
78
79 =head2 register_source
80
81 =over 4
82
83 =item Arguments: $moniker, $result_source
84
85 =back
86
87 Registers the L<DBIx::Class::ResultSource> in the schema with the given
88 moniker.
89
90 =cut
91
92 sub register_source {
93   my ($self, $moniker, $source) = @_;
94   my %reg = %{$self->source_registrations};
95   $reg{$moniker} = $source;
96   $self->source_registrations(\%reg);
97   $source->schema($self);
98   weaken($source->{schema}) if ref($self);
99   if ($source->result_class) {
100     my %map = %{$self->class_mappings};
101     $map{$source->result_class} = $moniker;
102     $self->class_mappings(\%map);
103   }
104 }
105
106 =head2 class
107
108 =over 4
109
110 =item Arguments: $moniker
111
112 =item Return Value: $classname
113
114 =back
115
116 Retrieves the result class name for the given moniker. For example:
117
118   my $class = $schema->class('CD');
119
120 =cut
121
122 sub class {
123   my ($self, $moniker) = @_;
124   return $self->source($moniker)->result_class;
125 }
126
127 =head2 source
128
129 =over 4
130
131 =item Arguments: $moniker
132
133 =item Return Value: $result_source
134
135 =back
136
137   my $source = $schema->source('Book');
138
139 Returns the L<DBIx::Class::ResultSource> object for the registered moniker.
140
141 =cut
142
143 sub source {
144   my ($self, $moniker) = @_;
145   my $sreg = $self->source_registrations;
146   return $sreg->{$moniker} if exists $sreg->{$moniker};
147
148   # if we got here, they probably passed a full class name
149   my $mapped = $self->class_mappings->{$moniker};
150   $self->throw_exception("Can't find source for ${moniker}")
151     unless $mapped && exists $sreg->{$mapped};
152   return $sreg->{$mapped};
153 }
154
155 =head2 sources
156
157 =over 4
158
159 =item Return Value: @source_monikers
160
161 =back
162
163 Returns the source monikers of all source registrations on this schema.
164 For example:
165
166   my @source_monikers = $schema->sources;
167
168 =cut
169
170 sub sources { return keys %{shift->source_registrations}; }
171
172 =head2 storage
173
174   my $storage = $schema->storage;
175
176 Returns the L<DBIx::Class::Storage> object for this Schema.
177
178 =head2 resultset
179
180 =over 4
181
182 =item Arguments: $moniker
183
184 =item Return Value: $result_set
185
186 =back
187
188   my $rs = $schema->resultset('DVD');
189
190 Returns the L<DBIx::Class::ResultSet> object for the registered moniker.
191
192 =cut
193
194 sub resultset {
195   my ($self, $moniker) = @_;
196   return $self->source($moniker)->resultset;
197 }
198
199 =head2 load_classes
200
201 =over 4
202
203 =item Arguments: @classes?, { $namespace => [ @classes ] }+
204
205 =back
206
207 With no arguments, this method uses L<Module::Find> to find all classes under
208 the schema's namespace. Otherwise, this method loads the classes you specify
209 (using L<use>), and registers them (using L</"register_class">).
210
211 It is possible to comment out classes with a leading C<#>, but note that perl
212 will think it's a mistake (trying to use a comment in a qw list), so you'll
213 need to add C<no warnings 'qw';> before your load_classes call.
214
215 Example:
216
217   My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
218                               # etc. (anything under the My::Schema namespace)
219
220   # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
221   # not Other::Namespace::LinerNotes nor My::Schema::Track
222   My::Schema->load_classes(qw/ CD Artist #Track /, {
223     Other::Namespace => [qw/ Producer #LinerNotes /],
224   });
225
226 =cut
227
228 sub load_classes {
229   my ($class, @params) = @_;
230
231   my %comps_for;
232
233   if (@params) {
234     foreach my $param (@params) {
235       if (ref $param eq 'ARRAY') {
236         # filter out commented entries
237         my @modules = grep { $_ !~ /^#/ } @$param;
238
239         push (@{$comps_for{$class}}, @modules);
240       }
241       elsif (ref $param eq 'HASH') {
242         # more than one namespace possible
243         for my $comp ( keys %$param ) {
244           # filter out commented entries
245           my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
246
247           push (@{$comps_for{$comp}}, @modules);
248         }
249       }
250       else {
251         # filter out commented entries
252         push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
253       }
254     }
255   } else {
256     eval "require Module::Find;";
257     $class->throw_exception(
258       "No arguments to load_classes and couldn't load Module::Find ($@)"
259     ) if $@;
260     my @comp = map { substr $_, length "${class}::"  }
261                  Module::Find::findallmod($class);
262     $comps_for{$class} = \@comp;
263   }
264
265   my @to_register;
266   {
267     no warnings qw/redefine/;
268     local *Class::C3::reinitialize = sub { };
269     foreach my $prefix (keys %comps_for) {
270       foreach my $comp (@{$comps_for{$prefix}||[]}) {
271         my $comp_class = "${prefix}::${comp}";
272         { # try to untaint module name. mods where this fails
273           # are left alone so we don't have to change the old behavior
274           no locale; # localized \w doesn't untaint expression
275           if ( $comp_class =~ m/^( (?:\w+::)* \w+ )$/x ) {
276             $comp_class = $1;
277           }
278         }
279         $class->ensure_class_loaded($comp_class);
280         $comp_class->source_name($comp) unless $comp_class->source_name;
281
282         push(@to_register, [ $comp_class->source_name, $comp_class ]);
283       }
284     }
285   }
286   Class::C3->reinitialize;
287
288   foreach my $to (@to_register) {
289     $class->register_class(@$to);
290     #  if $class->can('result_source_instance');
291   }
292 }
293
294 =head2 compose_connection
295
296 =over 4
297
298 =item Arguments: $target_namespace, @db_info
299
300 =item Return Value: $new_schema
301
302 =back
303
304 Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
305 calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
306 then injects the L<DBix::Class::ResultSetProxy> component and a
307 resultset_instance classdata entry on all the new classes, in order to support
308 $target_namespaces::$class->search(...) method calls.
309
310 This is primarily useful when you have a specific need for class method access
311 to a connection. In normal usage it is preferred to call
312 L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
313 on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
314 more information.
315
316 =cut
317
318 sub compose_connection {
319   my ($self, $target, @info) = @_;
320   my $base = 'DBIx::Class::ResultSetProxy';
321   eval "require ${base};";
322   $self->throw_exception
323     ("No arguments to load_classes and couldn't load ${base} ($@)")
324       if $@;
325
326   if ($self eq $target) {
327     # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
328     foreach my $moniker ($self->sources) {
329       my $source = $self->source($moniker);
330       my $class = $source->result_class;
331       $self->inject_base($class, $base);
332       $class->mk_classdata(resultset_instance => $source->resultset);
333       $class->mk_classdata(class_resolver => $self);
334     }
335     $self->connection(@info);
336     return $self;
337   }
338
339   my $schema = $self->compose_namespace($target, $base);
340   {
341     no strict 'refs';
342     *{"${target}::schema"} = sub { $schema };
343   }
344
345   $schema->connection(@info);
346   foreach my $moniker ($schema->sources) {
347     my $source = $schema->source($moniker);
348     my $class = $source->result_class;
349     #warn "$moniker $class $source ".$source->storage;
350     $class->mk_classdata(result_source_instance => $source);
351     $class->mk_classdata(resultset_instance => $source->resultset);
352     $class->mk_classdata(class_resolver => $schema);
353   }
354   return $schema;
355 }
356
357 =head2 compose_namespace
358
359 =over 4
360
361 =item Arguments: $target_namespace, $additional_base_class?
362
363 =item Return Value: $new_schema
364
365 =back
366
367 For each L<DBIx::Class::ResultSource> in the schema, this method creates a
368 class in the target namespace (e.g. $target_namespace::CD,
369 $target_namespace::Artist) that inherits from the corresponding classes
370 attached to the current schema.
371
372 It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
373 new $schema object. If C<$additional_base_class> is given, the new composed
374 classes will inherit from first the corresponding classe from the current
375 schema then the base class.
376
377 For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
378
379   $schema->compose_namespace('My::DB', 'Base::Class');
380   print join (', ', @My::DB::CD::ISA) . "\n";
381   print join (', ', @My::DB::Artist::ISA) ."\n";
382
383 will produce the output
384
385   My::Schema::CD, Base::Class
386   My::Schema::Artist, Base::Class
387
388 =cut
389
390 sub compose_namespace {
391   my ($self, $target, $base) = @_;
392   my $schema = $self->clone;
393   {
394     no warnings qw/redefine/;
395     local *Class::C3::reinitialize = sub { };
396     foreach my $moniker ($schema->sources) {
397       my $source = $schema->source($moniker);
398       my $target_class = "${target}::${moniker}";
399       $self->inject_base(
400         $target_class => $source->result_class, ($base ? $base : ())
401       );
402       $source->result_class($target_class);
403       $target_class->result_source_instance($source)
404         if $target_class->can('result_source_instance');
405     }
406   }
407   Class::C3->reinitialize();
408   {
409     no strict 'refs';
410     foreach my $meth (qw/class source resultset/) {
411       *{"${target}::${meth}"} =
412         sub { shift->schema->$meth(@_) };
413     }
414   }
415   return $schema;
416 }
417
418 =head2 setup_connection_class
419
420 =over 4
421
422 =item Arguments: $target, @info
423
424 =back
425
426 Sets up a database connection class to inject between the schema and the
427 subclasses that the schema creates.
428
429 =cut
430
431 sub setup_connection_class {
432   my ($class, $target, @info) = @_;
433   $class->inject_base($target => 'DBIx::Class::DB');
434   #$target->load_components('DB');
435   $target->connection(@info);
436 }
437
438 =head2 storage_type
439
440 =over 4
441
442 =item Arguments: $storage_type
443
444 =item Return Value: $storage_type
445
446 =back
447
448 Set the storage class that will be instantiated when L</connect> is called.
449 If the classname starts with C<::>, the prefix C<DBIx::Class::Storage> is
450 assumed by L</connect>.  Defaults to C<::DBI>,
451 which is L<DBIx::Class::Storage::DBI>.
452
453 You want to use this to hardcoded subclasses of L<DBIx::Class::Storage::DBI>
454 in cases where the appropriate subclass is not autodetected, such as when
455 dealing with MSSQL via L<DBD::Sybase>, in which case you'd set it to
456 C<::DBI::Sybase::MSSQL>.
457
458 =head2 connection
459
460 =over 4
461
462 =item Arguments: @args
463
464 =item Return Value: $new_schema
465
466 =back
467
468 Instantiates a new Storage object of type
469 L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
470 $storage->connect_info. Sets the connection in-place on the schema. See
471 L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
472
473 =cut
474
475 sub connection {
476   my ($self, @info) = @_;
477   return $self if !@info && $self->storage;
478   my $storage_class = $self->storage_type;
479   $storage_class = 'DBIx::Class::Storage'.$storage_class
480     if $storage_class =~ m/^::/;
481   eval "require ${storage_class};";
482   $self->throw_exception(
483     "No arguments to load_classes and couldn't load ${storage_class} ($@)"
484   ) if $@;
485   my $storage = $storage_class->new;
486   $storage->connect_info(\@info);
487   $self->storage($storage);
488   return $self;
489 }
490
491 =head2 connect
492
493 =over 4
494
495 =item Arguments: @info
496
497 =item Return Value: $new_schema
498
499 =back
500
501 This is a convenience method. It is equivalent to calling
502 $schema->clone->connection(@info). See L</connection> and L</clone> for more
503 information.
504
505 =cut
506
507 sub connect { shift->clone->connection(@_) }
508
509 =head2 txn_begin
510
511 Begins a transaction (does nothing if AutoCommit is off). Equivalent to
512 calling $schema->storage->txn_begin. See
513 L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
514
515 =cut
516
517 sub txn_begin { shift->storage->txn_begin }
518
519 =head2 txn_commit
520
521 Commits the current transaction. Equivalent to calling
522 $schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
523 for more information.
524
525 =cut
526
527 sub txn_commit { shift->storage->txn_commit }
528
529 =head2 txn_rollback
530
531 Rolls back the current transaction. Equivalent to calling
532 $schema->storage->txn_rollback. See
533 L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
534
535 =cut
536
537 sub txn_rollback { shift->storage->txn_rollback }
538
539 =head2 txn_do
540
541 =over 4
542
543 =item Arguments: C<$coderef>, @coderef_args?
544
545 =item Return Value: The return value of $coderef
546
547 =back
548
549 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
550 returning its result (if any). If an exception is caught, a rollback is issued
551 and the exception is rethrown. If the rollback fails, (i.e. throws an
552 exception) an exception is thrown that includes a "Rollback failed" message.
553
554 For example,
555
556   my $author_rs = $schema->resultset('Author')->find(1);
557   my @titles = qw/Night Day It/;
558
559   my $coderef = sub {
560     # If any one of these fails, the entire transaction fails
561     $author_rs->create_related('books', {
562       title => $_
563     }) foreach (@titles);
564
565     return $author->books;
566   };
567
568   my $rs;
569   eval {
570     $rs = $schema->txn_do($coderef);
571   };
572
573   if ($@) {                                  # Transaction failed
574     die "something terrible has happened!"   #
575       if ($@ =~ /Rollback failed/);          # Rollback failed
576
577     deal_with_failed_transaction();
578   }
579
580 In a nested transaction (calling txn_do() from within a txn_do() coderef) only
581 the outermost transaction will issue a L<DBIx::Class::Schema/"txn_commit"> on
582 the Schema's storage, and txn_do() can be called in void, scalar and list
583 context and it will behave as expected.
584
585 =cut
586
587 sub txn_do {
588   my ($self, $coderef, @args) = @_;
589
590   $self->storage or $self->throw_exception
591     ('txn_do called on $schema without storage');
592   ref $coderef eq 'CODE' or $self->throw_exception
593     ('$coderef must be a CODE reference');
594
595   my (@return_values, $return_value);
596
597   $self->txn_begin; # If this throws an exception, no rollback is needed
598
599   my $wantarray = wantarray; # Need to save this since the context
600                              # inside the eval{} block is independent
601                              # of the context that called txn_do()
602   eval {
603
604     # Need to differentiate between scalar/list context to allow for
605     # returning a list in scalar context to get the size of the list
606     if ($wantarray) {
607       # list context
608       @return_values = $coderef->(@args);
609     } elsif (defined $wantarray) {
610       # scalar context
611       $return_value = $coderef->(@args);
612     } else {
613       # void context
614       $coderef->(@args);
615     }
616     $self->txn_commit;
617   };
618
619   if ($@) {
620     my $error = $@;
621
622     eval {
623       $self->txn_rollback;
624     };
625
626     if ($@) {
627       my $rollback_error = $@;
628       my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
629       $self->throw_exception($error)  # propagate nested rollback
630         if $rollback_error =~ /$exception_class/;
631
632       $self->throw_exception(
633         "Transaction aborted: $error. Rollback failed: ${rollback_error}"
634       );
635     } else {
636       $self->throw_exception($error); # txn failed but rollback succeeded
637     }
638   }
639
640   return $wantarray ? @return_values : $return_value;
641 }
642
643 =head2 clone
644
645 =over 4
646
647 =item Return Value: $new_schema
648
649 =back
650
651 Clones the schema and its associated result_source objects and returns the
652 copy.
653
654 =cut
655
656 sub clone {
657   my ($self) = @_;
658   my $clone = { (ref $self ? %$self : ()) };
659   bless $clone, (ref $self || $self);
660
661   foreach my $moniker ($self->sources) {
662     my $source = $self->source($moniker);
663     my $new = $source->new($source);
664     $clone->register_source($moniker => $new);
665   }
666   return $clone;
667 }
668
669 =head2 populate
670
671 =over 4
672
673 =item Arguments: $source_name, \@data;
674
675 =back
676
677 Pass this method a resultsource name, and an arrayref of
678 arrayrefs. The arrayrefs should contain a list of column names,
679 followed by one or many sets of matching data for the given columns. 
680
681 Each set of data is inserted into the database using
682 L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
683 objects is returned.
684
685 i.e.,
686
687   $schema->populate('Artist', [
688     [ qw/artistid name/ ],
689     [ 1, 'Popular Band' ],
690     [ 2, 'Indie Band' ],
691     ...
692   ]);
693
694 =cut
695
696 sub populate {
697   my ($self, $name, $data) = @_;
698   my $rs = $self->resultset($name);
699   my @names = @{shift(@$data)};
700   my @created;
701   foreach my $item (@$data) {
702     my %create;
703     @create{@names} = @$item;
704     push(@created, $rs->create(\%create));
705   }
706   return @created;
707 }
708
709 =head2 throw_exception
710
711 =over 4
712
713 =item Arguments: $message
714
715 =back
716
717 Throws an exception. Defaults to using L<Carp::Clan> to report errors from
718 user's perspective.
719
720 =cut
721
722 sub throw_exception {
723   my ($self) = shift;
724   croak @_;
725 }
726
727 =head2 deploy (EXPERIMENTAL)
728
729 =over 4
730
731 =item Arguments: $sqlt_args, $dir
732
733 =back
734
735 Attempts to deploy the schema to the current storage using L<SQL::Translator>.
736
737 Note that this feature is currently EXPERIMENTAL and may not work correctly
738 across all databases, or fully handle complex relationships.
739
740 See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>. The most
741 common value for this would be C<< { add_drop_table => 1, } >> to have the SQL
742 produced include a DROP TABLE statement for each table created.
743
744 =cut
745
746 sub deploy {
747   my ($self, $sqltargs, $dir) = @_;
748   $self->throw_exception("Can't deploy without storage") unless $self->storage;
749   $self->storage->deploy($self, undef, $sqltargs, $dir);
750 }
751
752 =head2 create_ddl_dir (EXPERIMENTAL)
753
754 =over 4
755
756 =item Arguments: \@databases, $version, $directory, $sqlt_args
757
758 =back
759
760 Creates an SQL file based on the Schema, for each of the specified
761 database types, in the given directory.
762
763 Note that this feature is currently EXPERIMENTAL and may not work correctly
764 across all databases, or fully handle complex relationships.
765
766 =cut
767
768 sub create_ddl_dir {
769   my $self = shift;
770
771   $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
772   $self->storage->create_ddl_dir($self, @_);
773 }
774
775 =head2 ddl_filename (EXPERIMENTAL)
776
777   my $filename = $table->ddl_filename($type, $dir, $version)
778
779 Creates a filename for a SQL file based on the table class name.  Not
780 intended for direct end user use.
781
782 =cut
783
784 sub ddl_filename {
785     my ($self, $type, $dir, $version) = @_;
786
787     my $filename = ref($self);
788     $filename =~ s/::/-/g;
789     $filename = "$dir$filename-$version-$type.sql";
790
791     return $filename;
792 }
793
794 1;
795
796 =head1 AUTHORS
797
798 Matt S. Trout <mst@shadowcatsystems.co.uk>
799
800 =head1 LICENSE
801
802 You may distribute this code under the same terms as Perl itself.
803
804 =cut