more use_namespaces upgrade stuff, fix _table_filter
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
1 package DBIx::Class::Schema::Loader::Base;
2
3 use strict;
4 use warnings;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
6 use Class::C3;
7 use Carp::Clan qw/^DBIx::Class/;
8 use DBIx::Class::Schema::Loader::RelBuilder;
9 use Data::Dump qw/ dump /;
10 use POSIX qw//;
11 use File::Spec qw//;
12 use Cwd qw//;
13 use Digest::MD5 qw//;
14 use Lingua::EN::Inflect::Number qw//;
15 use File::Temp qw//;
16 use Class::Unload;
17 require DBIx::Class;
18
19 our $VERSION = '0.04999_13';
20
21 __PACKAGE__->mk_group_ro_accessors('simple', qw/
22                                 schema
23                                 schema_class
24
25                                 exclude
26                                 constraint
27                                 additional_classes
28                                 additional_base_classes
29                                 left_base_classes
30                                 components
31                                 resultset_components
32                                 skip_relationships
33                                 skip_load_external
34                                 moniker_map
35                                 inflect_singular
36                                 inflect_plural
37                                 debug
38                                 dump_directory
39                                 dump_overwrite
40                                 really_erase_my_files
41                                 result_namespace
42                                 resultset_namespace
43                                 default_resultset_class
44                                 schema_base_class
45                                 result_base_class
46                                 overwrite_modifications
47
48                                 relationship_attrs
49
50                                 db_schema
51                                 _tables
52                                 classes
53                                 _upgrading_classes
54                                 monikers
55                                 dynamic
56                                 naming
57 /);
58
59
60 __PACKAGE__->mk_group_accessors('simple', qw/
61                                 version_to_dump
62                                 schema_version_to_dump
63                                 _upgrading_from
64                                 _upgrading_from_load_classes
65                                 use_namespaces
66 /);
67
68 =head1 NAME
69
70 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
71
72 =head1 SYNOPSIS
73
74 See L<DBIx::Class::Schema::Loader>
75
76 =head1 DESCRIPTION
77
78 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
79 classes, and implements the common functionality between them.
80
81 =head1 CONSTRUCTOR OPTIONS
82
83 These constructor options are the base options for
84 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
85
86 =head2 skip_relationships
87
88 Skip setting up relationships.  The default is to attempt the loading
89 of relationships.
90
91 =head2 skip_load_external
92
93 Skip loading of other classes in @INC. The default is to merge all other classes
94 with the same name found in @INC into the schema file we are creating.
95
96 =head2 naming
97
98 Static schemas (ones dumped to disk) will, by default, use the new-style 0.05XXX
99 relationship names and singularized Results, unless you're overwriting an
100 existing dump made by a 0.04XXX version of L<DBIx::Class::Schema::Loader>, in
101 which case the backward compatible RelBuilder will be activated, and
102 singularization will be turned off.
103
104 Specifying
105
106     naming => 'v5'
107
108 will disable the backward-compatible RelBuilder and use
109 the new-style relationship names along with singularized Results, even when
110 overwriting a dump made with an earlier version.
111
112 The option also takes a hashref:
113
114     naming => { relationships => 'v5', monikers => 'v4' }
115
116 The keys are:
117
118 =over 4
119
120 =item relationships
121
122 How to name relationship accessors.
123
124 =item monikers
125
126 How to name Result classes.
127
128 =back
129
130 The values can be:
131
132 =over 4
133
134 =item current
135
136 Latest default style, whatever that happens to be.
137
138 =item v5
139
140 Version 0.05XXX style.
141
142 =item v4
143
144 Version 0.04XXX style.
145
146 =back
147
148 Dynamic schemas will always default to the 0.04XXX relationship names and won't
149 singularize Results for backward compatibility, to activate the new RelBuilder
150 and singularization put this in your C<Schema.pm> file:
151
152     __PACKAGE__->naming('current');
153
154 Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
155 next major version upgrade:
156
157     __PACKAGE__->naming('v5');
158
159 =head2 relationship_attrs
160
161 Hashref of attributes to pass to each generated relationship, listed
162 by type.  Also supports relationship type 'all', containing options to
163 pass to all generated relationships.  Attributes set for more specific
164 relationship types override those set in 'all'.
165
166 For example:
167
168   relationship_attrs => {
169     all      => { cascade_delete => 0 },
170     has_many => { cascade_delete => 1 },
171   },
172
173 will set the C<cascade_delete> option to 0 for all generated relationships,
174 except for C<has_many>, which will have cascade_delete as 1.
175
176 NOTE: this option is not supported if v4 backward-compatible naming is
177 set either globally (naming => 'v4') or just for relationships.
178
179 =head2 debug
180
181 If set to true, each constructive L<DBIx::Class> statement the loader
182 decides to execute will be C<warn>-ed before execution.
183
184 =head2 db_schema
185
186 Set the name of the schema to load (schema in the sense that your database
187 vendor means it).  Does not currently support loading more than one schema
188 name.
189
190 =head2 constraint
191
192 Only load tables matching regex.  Best specified as a qr// regex.
193
194 =head2 exclude
195
196 Exclude tables matching regex.  Best specified as a qr// regex.
197
198 =head2 moniker_map
199
200 Overrides the default table name to moniker translation.  Can be either
201 a hashref of table keys and moniker values, or a coderef for a translator
202 function taking a single scalar table name argument and returning
203 a scalar moniker.  If the hash entry does not exist, or the function
204 returns a false value, the code falls back to default behavior
205 for that table name.
206
207 The default behavior is to singularize the table name, and: C<join '', map
208 ucfirst, split /[\W_]+/, lc $table>, which is to say: lowercase everything,
209 split up the table name into chunks anywhere a non-alpha-numeric character
210 occurs, change the case of first letter of each chunk to upper case, and put
211 the chunks back together.  Examples:
212
213     Table Name  | Moniker Name
214     ---------------------------
215     luser       | Luser
216     luser_group | LuserGroup
217     luser-opts  | LuserOpt
218
219 =head2 inflect_plural
220
221 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
222 if hash key does not exist or coderef returns false), but acts as a map
223 for pluralizing relationship names.  The default behavior is to utilize
224 L<Lingua::EN::Inflect::Number/to_PL>.
225
226 =head2 inflect_singular
227
228 As L</inflect_plural> above, but for singularizing relationship names.
229 Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
230
231 =head2 schema_base_class
232
233 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
234
235 =head2 result_base_class
236
237 Base class for your table classes (aka result classes). Defaults to
238 'DBIx::Class::Core'.
239
240 =head2 additional_base_classes
241
242 List of additional base classes all of your table classes will use.
243
244 =head2 left_base_classes
245
246 List of additional base classes all of your table classes will use
247 that need to be leftmost.
248
249 =head2 additional_classes
250
251 List of additional classes which all of your table classes will use.
252
253 =head2 components
254
255 List of additional components to be loaded into all of your table
256 classes.  A good example would be C<ResultSetManager>.
257
258 =head2 resultset_components
259
260 List of additional ResultSet components to be loaded into your table
261 classes.  A good example would be C<AlwaysRS>.  Component
262 C<ResultSetManager> will be automatically added to the above
263 C<components> list if this option is set.
264
265 =head2 use_namespaces
266
267 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
268 a C<0>.
269
270 Generate result class names suitable for
271 L<DBIx::Class::Schema/load_namespaces> and call that instead of
272 L<DBIx::Class::Schema/load_classes>. When using this option you can also
273 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
274 C<resultset_namespace>, C<default_resultset_class>), and they will be added
275 to the call (and the generated result class names adjusted appropriately).
276
277 =head2 dump_directory
278
279 This option is designed to be a tool to help you transition from this
280 loader to a manually-defined schema when you decide it's time to do so.
281
282 The value of this option is a perl libdir pathname.  Within
283 that directory this module will create a baseline manual
284 L<DBIx::Class::Schema> module set, based on what it creates at runtime
285 in memory.
286
287 The created schema class will have the same classname as the one on
288 which you are setting this option (and the ResultSource classes will be
289 based on this name as well).
290
291 Normally you wouldn't hard-code this setting in your schema class, as it
292 is meant for one-time manual usage.
293
294 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
295 recommended way to access this functionality.
296
297 =head2 dump_overwrite
298
299 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
300 the same thing as the old C<dump_overwrite> setting from previous releases.
301
302 =head2 really_erase_my_files
303
304 Default false.  If true, Loader will unconditionally delete any existing
305 files before creating the new ones from scratch when dumping a schema to disk.
306
307 The default behavior is instead to only replace the top portion of the
308 file, up to and including the final stanza which contains
309 C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
310 leaving any customizations you placed after that as they were.
311
312 When C<really_erase_my_files> is not set, if the output file already exists,
313 but the aforementioned final stanza is not found, or the checksum
314 contained there does not match the generated contents, Loader will
315 croak and not touch the file.
316
317 You should really be using version control on your schema classes (and all
318 of the rest of your code for that matter).  Don't blame me if a bug in this
319 code wipes something out when it shouldn't have, you've been warned.
320
321 =head2 overwrite_modifications
322
323 Default false.  If false, when updating existing files, Loader will
324 refuse to modify any Loader-generated code that has been modified
325 since its last run (as determined by the checksum Loader put in its
326 comment lines).
327
328 If true, Loader will discard any manual modifications that have been
329 made to Loader-generated code.
330
331 Again, you should be using version control on your schema classes.  Be
332 careful with this option.
333
334 =head1 METHODS
335
336 None of these methods are intended for direct invocation by regular
337 users of L<DBIx::Class::Schema::Loader>.  Anything you can find here
338 can also be found via standard L<DBIx::Class::Schema> methods somehow.
339
340 =cut
341
342 use constant CURRENT_V => 'v5';
343
344 # ensure that a peice of object data is a valid arrayref, creating
345 # an empty one or encapsulating whatever's there.
346 sub _ensure_arrayref {
347     my $self = shift;
348
349     foreach (@_) {
350         $self->{$_} ||= [];
351         $self->{$_} = [ $self->{$_} ]
352             unless ref $self->{$_} eq 'ARRAY';
353     }
354 }
355
356 =head2 new
357
358 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
359 by L<DBIx::Class::Schema::Loader>.
360
361 =cut
362
363 sub new {
364     my ( $class, %args ) = @_;
365
366     my $self = { %args };
367
368     bless $self => $class;
369
370     $self->_ensure_arrayref(qw/additional_classes
371                                additional_base_classes
372                                left_base_classes
373                                components
374                                resultset_components
375                               /);
376
377     push(@{$self->{components}}, 'ResultSetManager')
378         if @{$self->{resultset_components}};
379
380     $self->{monikers} = {};
381     $self->{classes} = {};
382     $self->{_upgrading_classes} = {};
383
384     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
385     $self->{schema} ||= $self->{schema_class};
386
387     croak "dump_overwrite is deprecated.  Please read the"
388         . " DBIx::Class::Schema::Loader::Base documentation"
389             if $self->{dump_overwrite};
390
391     $self->{dynamic} = ! $self->{dump_directory};
392     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
393                                                      TMPDIR  => 1,
394                                                      CLEANUP => 1,
395                                                    );
396
397     $self->{dump_directory} ||= $self->{temp_directory};
398
399     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
400     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
401
402     if ((not ref $self->naming) && defined $self->naming) {
403         my $naming_ver = $self->naming;
404         $self->{naming} = {
405             relationships => $naming_ver,
406             monikers => $naming_ver,
407         };
408     }
409
410     if ($self->naming) {
411         for (values %{ $self->naming }) {
412             $_ = CURRENT_V if $_ eq 'current';
413         }
414     }
415     $self->{naming} ||= {};
416
417     $self->_check_back_compat;
418
419     $self->use_namespaces(1) unless defined $self->use_namespaces;
420
421     $self;
422 }
423
424 sub _check_back_compat {
425     my ($self) = @_;
426
427 # dynamic schemas will always be in 0.04006 mode, unless overridden
428     if ($self->dynamic) {
429 # just in case, though no one is likely to dump a dynamic schema
430         $self->schema_version_to_dump('0.04006');
431
432         if (not %{ $self->naming }) {
433             warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
434
435 Dynamic schema detected, will run in 0.04006 mode.
436
437 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
438 to disable this warning.
439
440 Also consider setting 'use_namespaces => 1' if/when upgrading.
441
442 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
443 details.
444 EOF
445         }
446         else {
447             $self->_upgrading_from('v4');
448         }
449
450         $self->naming->{relationships} ||= 'v4';
451         $self->naming->{monikers}      ||= 'v4';
452
453         if ($self->use_namespaces) {
454             $self->_upgrading_from_load_classes(1);
455         }
456         else {
457             $self->use_namespaces(0);
458         }
459
460         return;
461     }
462
463 # otherwise check if we need backcompat mode for a static schema
464     my $filename = $self->_get_dump_filename($self->schema_class);
465     return unless -e $filename;
466
467     open(my $fh, '<', $filename)
468         or croak "Cannot open '$filename' for reading: $!";
469
470     my $load_classes = 0;
471
472     while (<$fh>) {
473         if (/^__PACKAGE__->load_classes;/) {
474             $load_classes = 1;
475         } elsif (my ($real_ver) =
476                 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
477
478             if ($load_classes && (not defined $self->use_namespaces)) {
479                 warn <<"EOF"  unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
480
481 'load_classes;' static schema detected, turning off use_namespaces.
482
483 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
484 variable to disable this warning.
485
486 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
487 details.
488 EOF
489                 $self->use_namespaces(0);
490             }
491             elsif ($load_classes && $self->use_namespaces) {
492                 $self->use_namespaces(1);
493                 $self->_upgrading_from_load_classes(1);
494             }
495
496             # XXX when we go past .0 this will need fixing
497             my ($v) = $real_ver =~ /([1-9])/;
498             $v = "v$v";
499
500             last if $v eq CURRENT_V || $real_ver =~ /^0\.\d\d999/;
501
502             if (not %{ $self->naming }) {
503                 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
504
505 Version $real_ver static schema detected, turning on backcompat mode.
506
507 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
508 to disable this warning.
509
510 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
511 details.
512 EOF
513             }
514             else {
515                 $self->_upgrading_from($v);
516                 last;
517             }
518
519             $self->naming->{relationships} ||= $v;
520             $self->naming->{monikers}      ||= $v;
521
522             $self->schema_version_to_dump($real_ver);
523
524             $self->use_namespaces(0) unless defined $self->use_namespaces;
525
526             last;
527         }
528     }
529     close $fh;
530 }
531
532 sub _find_file_in_inc {
533     my ($self, $file) = @_;
534
535     foreach my $prefix (@INC) {
536         my $fullpath = File::Spec->catfile($prefix, $file);
537         return $fullpath if -f $fullpath
538             and Cwd::abs_path($fullpath) ne
539                (Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '');
540     }
541
542     return;
543 }
544
545 sub _class_path {
546     my ($self, $class) = @_;
547
548     my $class_path = $class;
549     $class_path =~ s{::}{/}g;
550     $class_path .= '.pm';
551
552     return $class_path;
553 }
554
555 sub _find_class_in_inc {
556     my ($self, $class) = @_;
557
558     return $self->_find_file_in_inc($self->_class_path($class));
559 }
560
561 sub _rewrite_old_classnames {
562     my ($self, $code) = @_;
563
564     return $code unless $self->_upgrading_from;
565
566     my %old_classes = reverse %{ $self->_upgrading_classes };
567
568     my $re = join '|', keys %old_classes;
569     $re = qr/\b($re)\b/;
570
571     $code =~ s/$re/$old_classes{$1} || $1/eg;
572
573     return $code;
574 }
575
576 sub _load_external {
577     my ($self, $class) = @_;
578
579     return if $self->{skip_load_external};
580
581     # so that we don't load our own classes, under any circumstances
582     local *INC = [ grep $_ ne $self->dump_directory, @INC ];
583
584     my $real_inc_path = $self->_find_class_in_inc($class);
585
586     my $old_class = $self->_upgrading_classes->{$class}
587         if $self->_upgrading_from;
588
589     my $old_real_inc_path = $self->_find_class_in_inc($old_class)
590         if $old_class && $old_class ne $class;
591
592     return unless $real_inc_path || $old_real_inc_path;
593
594     if ($real_inc_path) {
595         # If we make it to here, we loaded an external definition
596         warn qq/# Loaded external class definition for '$class'\n/
597             if $self->debug;
598
599         open(my $fh, '<', $real_inc_path)
600             or croak "Failed to open '$real_inc_path' for reading: $!";
601         my $code = do { local $/; <$fh> };
602         close($fh)
603             or croak "Failed to close $real_inc_path: $!";
604         $code = $self->_rewrite_old_classnames($code);
605
606         if ($self->dynamic) { # load the class too
607             # kill redefined warnings
608             my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
609             local $SIG{__WARN__} = sub {
610                 $warn_handler->(@_)
611                     unless $_[0] =~ /^Subroutine \S+ redefined/;
612             };
613             eval $code;
614             die $@ if $@;
615         }
616
617         $self->_ext_stmt($class,
618           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
619          .qq|# They are now part of the custom portion of this file\n|
620          .qq|# for you to hand-edit.  If you do not either delete\n|
621          .qq|# this section or remove that file from \@INC, this section\n|
622          .qq|# will be repeated redundantly when you re-create this\n|
623          .qq|# file again via Loader!  See skip_load_external to disable\n|
624          .qq|# this feature.\n|
625         );
626         chomp $code;
627         $self->_ext_stmt($class, $code);
628         $self->_ext_stmt($class,
629             qq|# End of lines loaded from '$real_inc_path' |
630         );
631     }
632
633     if ($old_real_inc_path) {
634         open(my $fh, '<', $old_real_inc_path)
635             or croak "Failed to open '$old_real_inc_path' for reading: $!";
636         $self->_ext_stmt($class, <<"EOF");
637
638 # These lines were loaded from '$old_real_inc_path',
639 # based on the Result class name that would have been created by an 0.04006
640 # version of the Loader. For a static schema, this happens only once during
641 # upgrade. See skip_load_external to disable this feature.
642 EOF
643
644         my $code = do {
645             local ($/, @ARGV) = (undef, $old_real_inc_path); <>
646         };
647         $code = $self->_rewrite_old_classnames($code);
648
649         if ($self->dynamic) {
650             warn <<"EOF";
651
652 Detected external content in '$old_real_inc_path', a class name that would have
653 been used by an 0.04006 version of the Loader.
654
655 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
656 new name of the Result.
657 EOF
658             # kill redefined warnings
659             my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
660             local $SIG{__WARN__} = sub {
661                 $warn_handler->(@_)
662                     unless $_[0] =~ /^Subroutine \S+ redefined/;
663             };
664             eval $code;
665             die $@ if $@;
666         }
667
668         chomp $code;
669         $self->_ext_stmt($class, $code);
670         $self->_ext_stmt($class,
671             qq|# End of lines loaded from '$old_real_inc_path' |
672         );
673     }
674 }
675
676 =head2 load
677
678 Does the actual schema-construction work.
679
680 =cut
681
682 sub load {
683     my $self = shift;
684
685     $self->_load_tables($self->_tables_list);
686 }
687
688 =head2 rescan
689
690 Arguments: schema
691
692 Rescan the database for newly added tables.  Does
693 not process drops or changes.  Returns a list of
694 the newly added table monikers.
695
696 The schema argument should be the schema class
697 or object to be affected.  It should probably
698 be derived from the original schema_class used
699 during L</load>.
700
701 =cut
702
703 sub rescan {
704     my ($self, $schema) = @_;
705
706     $self->{schema} = $schema;
707     $self->_relbuilder->{schema} = $schema;
708
709     my @created;
710     my @current = $self->_tables_list;
711     foreach my $table ($self->_tables_list) {
712         if(!exists $self->{_tables}->{$table}) {
713             push(@created, $table);
714         }
715     }
716
717     my $loaded = $self->_load_tables(@created);
718
719     return map { $self->monikers->{$_} } @$loaded;
720 }
721
722 sub _relbuilder {
723     no warnings 'uninitialized';
724     my ($self) = @_;
725
726     return if $self->{skip_relationships};
727
728     if ($self->naming->{relationships} eq 'v4') {
729         require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
730         return $self->{relbuilder} ||=
731             DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
732                 $self->schema, $self->inflect_plural, $self->inflect_singular
733             );
734     }
735
736     $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
737          $self->schema,
738          $self->inflect_plural,
739          $self->inflect_singular,
740          $self->relationship_attrs,
741     );
742 }
743
744 sub _load_tables {
745     my ($self, @tables) = @_;
746
747     # First, use _tables_list with constraint and exclude
748     #  to get a list of tables to operate on
749
750     my $constraint   = $self->constraint;
751     my $exclude      = $self->exclude;
752
753     @tables = grep { /$constraint/ } @tables if $constraint;
754     @tables = grep { ! /$exclude/ } @tables if $exclude;
755
756     # Save the new tables to the tables list
757     foreach (@tables) {
758         $self->{_tables}->{$_} = 1;
759     }
760
761     $self->_make_src_class($_) for @tables;
762     $self->_setup_src_meta($_) for @tables;
763
764     if(!$self->skip_relationships) {
765         # The relationship loader needs a working schema
766         $self->{quiet} = 1;
767         local $self->{dump_directory} = $self->{temp_directory};
768         $self->_reload_classes(\@tables);
769         $self->_load_relationships($_) for @tables;
770         $self->{quiet} = 0;
771
772         # Remove that temp dir from INC so it doesn't get reloaded
773         @INC = grep $_ ne $self->dump_directory, @INC;
774     }
775
776     $self->_load_external($_)
777         for map { $self->classes->{$_} } @tables;
778
779     # Reload without unloading first to preserve any symbols from external
780     # packages.
781     $self->_reload_classes(\@tables, 0);
782
783     # Drop temporary cache
784     delete $self->{_cache};
785
786     return \@tables;
787 }
788
789 sub _reload_classes {
790     my ($self, $tables, $unload) = @_;
791
792     my @tables = @$tables;
793     $unload = 1 unless defined $unload;
794
795     # so that we don't repeat custom sections
796     @INC = grep $_ ne $self->dump_directory, @INC;
797
798     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
799
800     unshift @INC, $self->dump_directory;
801     
802     my @to_register;
803     my %have_source = map { $_ => $self->schema->source($_) }
804         $self->schema->sources;
805
806     for my $table (@tables) {
807         my $moniker = $self->monikers->{$table};
808         my $class = $self->classes->{$table};
809         
810         {
811             no warnings 'redefine';
812             local *Class::C3::reinitialize = sub {};
813             use warnings;
814
815             Class::Unload->unload($class) if $unload;
816             my ($source, $resultset_class);
817             if (
818                 ($source = $have_source{$moniker})
819                 && ($resultset_class = $source->resultset_class)
820                 && ($resultset_class ne 'DBIx::Class::ResultSet')
821             ) {
822                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
823                 Class::Unload->unload($resultset_class) if $unload;
824                 $self->_reload_class($resultset_class) if $has_file;
825             }
826             $self->_reload_class($class);
827         }
828         push @to_register, [$moniker, $class];
829     }
830
831     Class::C3->reinitialize;
832     for (@to_register) {
833         $self->schema->register_class(@$_);
834     }
835 }
836
837 # We use this instead of ensure_class_loaded when there are package symbols we
838 # want to preserve.
839 sub _reload_class {
840     my ($self, $class) = @_;
841
842     my $class_path = $self->_class_path($class);
843     delete $INC{ $class_path };
844
845 # kill redefined warnings
846     my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
847     local $SIG{__WARN__} = sub {
848         $warn_handler->(@_)
849             unless $_[0] =~ /^Subroutine \S+ redefined/;
850     };
851     eval "require $class;";
852 }
853
854 sub _get_dump_filename {
855     my ($self, $class) = (@_);
856
857     $class =~ s{::}{/}g;
858     return $self->dump_directory . q{/} . $class . q{.pm};
859 }
860
861 sub _ensure_dump_subdirs {
862     my ($self, $class) = (@_);
863
864     my @name_parts = split(/::/, $class);
865     pop @name_parts; # we don't care about the very last element,
866                      # which is a filename
867
868     my $dir = $self->dump_directory;
869     while (1) {
870         if(!-d $dir) {
871             mkdir($dir) or croak "mkdir('$dir') failed: $!";
872         }
873         last if !@name_parts;
874         $dir = File::Spec->catdir($dir, shift @name_parts);
875     }
876 }
877
878 sub _dump_to_dir {
879     my ($self, @classes) = @_;
880
881     my $schema_class = $self->schema_class;
882     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
883
884     my $target_dir = $self->dump_directory;
885     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
886         unless $self->{dynamic} or $self->{quiet};
887
888     my $schema_text =
889           qq|package $schema_class;\n\n|
890         . qq|# Created by DBIx::Class::Schema::Loader\n|
891         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
892         . qq|use strict;\nuse warnings;\n\n|
893         . qq|use base '$schema_base_class';\n\n|;
894
895     if ($self->use_namespaces) {
896         $schema_text .= qq|__PACKAGE__->load_namespaces|;
897         my $namespace_options;
898         for my $attr (qw(result_namespace
899                          resultset_namespace
900                          default_resultset_class)) {
901             if ($self->$attr) {
902                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
903             }
904         }
905         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
906         $schema_text .= qq|;\n|;
907     }
908     else {
909         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
910     }
911
912     {
913         local $self->{version_to_dump} = $self->schema_version_to_dump;
914         $self->_write_classfile($schema_class, $schema_text, 1);
915     }
916
917     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
918
919     foreach my $src_class (@classes) {
920         my $src_text = 
921               qq|package $src_class;\n\n|
922             . qq|# Created by DBIx::Class::Schema::Loader\n|
923             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
924             . qq|use strict;\nuse warnings;\n\n|
925             . qq|use base '$result_base_class';\n\n|;
926
927         $self->_write_classfile($src_class, $src_text);
928     }
929
930     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
931
932 }
933
934 sub _sig_comment {
935     my ($self, $version, $ts) = @_;
936     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
937          . qq| v| . $version
938          . q| @ | . $ts 
939          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
940 }
941
942 sub _write_classfile {
943     my ($self, $class, $text, $is_schema) = @_;
944
945     my $filename = $self->_get_dump_filename($class);
946     $self->_ensure_dump_subdirs($class);
947
948     if (-f $filename && $self->really_erase_my_files) {
949         warn "Deleting existing file '$filename' due to "
950             . "'really_erase_my_files' setting\n" unless $self->{quiet};
951         unlink($filename);
952     }    
953
954     my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
955
956     if (my $old_class = $self->_upgrading_classes->{$class}) {
957         my $old_filename = $self->_get_dump_filename($old_class);
958
959         my ($old_custom_content) = $self->_get_custom_content(
960             $old_class, $old_filename, 0 # do not add default comment
961         );
962
963         $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
964
965         if ($old_custom_content) {
966             $custom_content =
967                 "\n" . $old_custom_content . "\n" . $custom_content;
968         }
969
970         unlink $old_filename;
971     }
972
973     $custom_content = $self->_rewrite_old_classnames($custom_content);
974
975     $text .= qq|$_\n|
976         for @{$self->{_dump_storage}->{$class} || []};
977
978     # Check and see if the dump is infact differnt
979
980     my $compare_to;
981     if ($old_md5) {
982       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
983       
984
985       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
986         return unless $self->_upgrading_from && $is_schema;
987       }
988     }
989
990     $text .= $self->_sig_comment(
991       $self->version_to_dump,
992       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
993     );
994
995     open(my $fh, '>', $filename)
996         or croak "Cannot open '$filename' for writing: $!";
997
998     # Write the top half and its MD5 sum
999     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1000
1001     # Write out anything loaded via external partial class file in @INC
1002     print $fh qq|$_\n|
1003         for @{$self->{_ext_storage}->{$class} || []};
1004
1005     # Write out any custom content the user has added
1006     print $fh $custom_content;
1007
1008     close($fh)
1009         or croak "Error closing '$filename': $!";
1010 }
1011
1012 sub _default_custom_content {
1013     return qq|\n\n# You can replace this text with custom|
1014          . qq| content, and it will be preserved on regeneration|
1015          . qq|\n1;\n|;
1016 }
1017
1018 sub _get_custom_content {
1019     my ($self, $class, $filename, $add_default) = @_;
1020
1021     $add_default = 1 unless defined $add_default;
1022
1023     return ($self->_default_custom_content) if ! -f $filename;
1024
1025     open(my $fh, '<', $filename)
1026         or croak "Cannot open '$filename' for reading: $!";
1027
1028     my $mark_re = 
1029         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1030
1031     my $buffer = '';
1032     my ($md5, $ts, $ver);
1033     while(<$fh>) {
1034         if(!$md5 && /$mark_re/) {
1035             $md5 = $2;
1036             my $line = $1;
1037
1038             # Pull out the previous version and timestamp
1039             ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
1040
1041             $buffer .= $line;
1042             croak "Checksum mismatch in '$filename', the auto-generated part of the file has been modified outside of this loader.  Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1043                 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
1044
1045             $buffer = '';
1046         }
1047         else {
1048             $buffer .= $_;
1049         }
1050     }
1051
1052     croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
1053         . " it does not appear to have been generated by Loader"
1054             if !$md5;
1055
1056     # Default custom content:
1057     $buffer ||= $self->_default_custom_content if $add_default;
1058
1059     return ($buffer, $md5, $ver, $ts);
1060 }
1061
1062 sub _use {
1063     my $self = shift;
1064     my $target = shift;
1065
1066     foreach (@_) {
1067         warn "$target: use $_;" if $self->debug;
1068         $self->_raw_stmt($target, "use $_;");
1069     }
1070 }
1071
1072 sub _inject {
1073     my $self = shift;
1074     my $target = shift;
1075     my $schema_class = $self->schema_class;
1076
1077     my $blist = join(q{ }, @_);
1078     warn "$target: use base qw/ $blist /;" if $self->debug && @_;
1079     $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
1080 }
1081
1082 # Create class with applicable bases, setup monikers, etc
1083 sub _make_src_class {
1084     my ($self, $table) = @_;
1085
1086     my $schema       = $self->schema;
1087     my $schema_class = $self->schema_class;
1088
1089     my $table_moniker = $self->_table2moniker($table);
1090     my @result_namespace = ($schema_class);
1091     if ($self->use_namespaces) {
1092         my $result_namespace = $self->result_namespace || 'Result';
1093         if ($result_namespace =~ /^\+(.*)/) {
1094             # Fully qualified namespace
1095             @result_namespace =  ($1)
1096         }
1097         else {
1098             # Relative namespace
1099             push @result_namespace, $result_namespace;
1100         }
1101     }
1102     my $table_class = join(q{::}, @result_namespace, $table_moniker);
1103
1104     if ((my $upgrading_v = $self->_upgrading_from)
1105             || $self->_upgrading_from_load_classes) {
1106         local $self->naming->{monikers} = $upgrading_v
1107             if $upgrading_v;
1108
1109         my @result_namespace = @result_namespace;
1110         @result_namespace = ($schema_class)
1111             if $self->_upgrading_from_load_classes;
1112
1113         my $old_class = join(q{::}, @result_namespace,
1114             $self->_table2moniker($table));
1115
1116         $self->_upgrading_classes->{$table_class} = $old_class
1117             unless $table_class eq $old_class;
1118     }
1119
1120     my $table_normalized = lc $table;
1121     $self->classes->{$table} = $table_class;
1122     $self->classes->{$table_normalized} = $table_class;
1123     $self->monikers->{$table} = $table_moniker;
1124     $self->monikers->{$table_normalized} = $table_moniker;
1125
1126     $self->_use   ($table_class, @{$self->additional_classes});
1127     $self->_inject($table_class, @{$self->left_base_classes});
1128
1129     if (my @components = @{ $self->components }) {
1130         $self->_dbic_stmt($table_class, 'load_components', @components);
1131     }
1132
1133     $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1134         if @{$self->resultset_components};
1135     $self->_inject($table_class, @{$self->additional_base_classes});
1136 }
1137
1138 # Set up metadata (cols, pks, etc)
1139 sub _setup_src_meta {
1140     my ($self, $table) = @_;
1141
1142     my $schema       = $self->schema;
1143     my $schema_class = $self->schema_class;
1144
1145     my $table_class = $self->classes->{$table};
1146     my $table_moniker = $self->monikers->{$table};
1147
1148     my $table_name = $table;
1149     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
1150
1151     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1152         $table_name = \ $self->_quote_table_name($table_name);
1153     }
1154
1155     $self->_dbic_stmt($table_class,'table',$table_name);
1156
1157     my $cols = $self->_table_columns($table);
1158     my $col_info;
1159     eval { $col_info = $self->_columns_info_for($table) };
1160     if($@) {
1161         $self->_dbic_stmt($table_class,'add_columns',@$cols);
1162     }
1163     else {
1164         if ($self->_is_case_sensitive) {
1165             for my $col (keys %$col_info) {
1166                 $col_info->{$col}{accessor} = lc $col
1167                     if $col ne lc($col);
1168             }
1169         } else {
1170             $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1171         }
1172
1173         my $fks = $self->_table_fk_info($table);
1174
1175         for my $fkdef (@$fks) {
1176             for my $col (@{ $fkdef->{local_columns} }) {
1177                 $col_info->{$col}{is_foreign_key} = 1;
1178             }
1179         }
1180         $self->_dbic_stmt(
1181             $table_class,
1182             'add_columns',
1183             map { $_, ($col_info->{$_}||{}) } @$cols
1184         );
1185     }
1186
1187     my %uniq_tag; # used to eliminate duplicate uniqs
1188
1189     my $pks = $self->_table_pk_info($table) || [];
1190     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1191           : carp("$table has no primary key");
1192     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1193
1194     my $uniqs = $self->_table_uniq_info($table) || [];
1195     for (@$uniqs) {
1196         my ($name, $cols) = @$_;
1197         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1198         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1199     }
1200
1201 }
1202
1203 =head2 tables
1204
1205 Returns a sorted list of loaded tables, using the original database table
1206 names.
1207
1208 =cut
1209
1210 sub tables {
1211     my $self = shift;
1212
1213     return keys %{$self->_tables};
1214 }
1215
1216 # Make a moniker from a table
1217 sub _default_table2moniker {
1218     no warnings 'uninitialized';
1219     my ($self, $table) = @_;
1220
1221     if ($self->naming->{monikers} eq 'v4') {
1222         return join '', map ucfirst, split /[\W_]+/, lc $table;
1223     }
1224
1225     return join '', map ucfirst, split /[\W_]+/,
1226         Lingua::EN::Inflect::Number::to_S(lc $table);
1227 }
1228
1229 sub _table2moniker {
1230     my ( $self, $table ) = @_;
1231
1232     my $moniker;
1233
1234     if( ref $self->moniker_map eq 'HASH' ) {
1235         $moniker = $self->moniker_map->{$table};
1236     }
1237     elsif( ref $self->moniker_map eq 'CODE' ) {
1238         $moniker = $self->moniker_map->($table);
1239     }
1240
1241     $moniker ||= $self->_default_table2moniker($table);
1242
1243     return $moniker;
1244 }
1245
1246 sub _load_relationships {
1247     my ($self, $table) = @_;
1248
1249     my $tbl_fk_info = $self->_table_fk_info($table);
1250     foreach my $fkdef (@$tbl_fk_info) {
1251         $fkdef->{remote_source} =
1252             $self->monikers->{delete $fkdef->{remote_table}};
1253     }
1254     my $tbl_uniq_info = $self->_table_uniq_info($table);
1255
1256     my $local_moniker = $self->monikers->{$table};
1257     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1258
1259     foreach my $src_class (sort keys %$rel_stmts) {
1260         my $src_stmts = $rel_stmts->{$src_class};
1261         foreach my $stmt (@$src_stmts) {
1262             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1263         }
1264     }
1265 }
1266
1267 # Overload these in driver class:
1268
1269 # Returns an arrayref of column names
1270 sub _table_columns { croak "ABSTRACT METHOD" }
1271
1272 # Returns arrayref of pk col names
1273 sub _table_pk_info { croak "ABSTRACT METHOD" }
1274
1275 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1276 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1277
1278 # Returns an arrayref of foreign key constraints, each
1279 #   being a hashref with 3 keys:
1280 #   local_columns (arrayref), remote_columns (arrayref), remote_table
1281 sub _table_fk_info { croak "ABSTRACT METHOD" }
1282
1283 # Returns an array of lower case table names
1284 sub _tables_list { croak "ABSTRACT METHOD" }
1285
1286 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1287 sub _dbic_stmt {
1288     my $self   = shift;
1289     my $class  = shift;
1290     my $method = shift;
1291
1292     # generate the pod for this statement, storing it with $self->_pod
1293     $self->_make_pod( $class, $method, @_ );
1294
1295     my $args = dump(@_);
1296     $args = '(' . $args . ')' if @_ < 2;
1297     my $stmt = $method . $args . q{;};
1298
1299     warn qq|$class\->$stmt\n| if $self->debug;
1300     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1301     return;
1302 }
1303
1304 # generates the accompanying pod for a DBIC class method statement,
1305 # storing it with $self->_pod
1306 sub _make_pod {
1307     my $self   = shift;
1308     my $class  = shift;
1309     my $method = shift;
1310
1311     if ( $method eq 'table' ) {
1312         my ($table) = @_;
1313         $self->_pod( $class, "=head1 NAME" );
1314         my $table_descr = $class;
1315         if ( $self->can('_table_comment') ) {
1316             my $comment = $self->_table_comment($table);
1317             $table_descr .= " - " . $comment if $comment;
1318         }
1319         $self->{_class2table}{ $class } = $table;
1320         $self->_pod( $class, $table_descr );
1321         $self->_pod_cut( $class );
1322     } elsif ( $method eq 'add_columns' ) {
1323         $self->_pod( $class, "=head1 ACCESSORS" );
1324         my $col_counter = 0;
1325         my @cols = @_;
1326         while( my ($name,$attrs) = splice @cols,0,2 ) {
1327             $col_counter++;
1328             $self->_pod( $class, '=head2 ' . $name  );
1329             $self->_pod( $class,
1330                          join "\n", map {
1331                              my $s = $attrs->{$_};
1332                              $s = !defined $s      ? 'undef'          :
1333                                   length($s) == 0  ? '(empty string)' :
1334                                                      $s;
1335
1336                              "  $_: $s"
1337                          } sort keys %$attrs,
1338                        );
1339
1340             if( $self->can('_column_comment')
1341                 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1342               ) {
1343                 $self->_pod( $class, $comment );
1344             }
1345         }
1346         $self->_pod_cut( $class );
1347     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1348         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1349         my ( $accessor, $rel_class ) = @_;
1350         $self->_pod( $class, "=head2 $accessor" );
1351         $self->_pod( $class, 'Type: ' . $method );
1352         $self->_pod( $class, "Related object: L<$rel_class>" );
1353         $self->_pod_cut( $class );
1354         $self->{_relations_started} { $class } = 1;
1355     }
1356 }
1357
1358 # Stores a POD documentation
1359 sub _pod {
1360     my ($self, $class, $stmt) = @_;
1361     $self->_raw_stmt( $class, "\n" . $stmt  );
1362 }
1363
1364 sub _pod_cut {
1365     my ($self, $class ) = @_;
1366     $self->_raw_stmt( $class, "\n=cut\n" );
1367 }
1368
1369
1370 # Store a raw source line for a class (for dumping purposes)
1371 sub _raw_stmt {
1372     my ($self, $class, $stmt) = @_;
1373     push(@{$self->{_dump_storage}->{$class}}, $stmt);
1374 }
1375
1376 # Like above, but separately for the externally loaded stuff
1377 sub _ext_stmt {
1378     my ($self, $class, $stmt) = @_;
1379     push(@{$self->{_ext_storage}->{$class}}, $stmt);
1380 }
1381
1382 sub _quote_table_name {
1383     my ($self, $table) = @_;
1384
1385     my $qt = $self->schema->storage->sql_maker->quote_char;
1386
1387     return $table unless $qt;
1388
1389     if (ref $qt) {
1390         return $qt->[0] . $table . $qt->[1];
1391     }
1392
1393     return $qt . $table . $qt;
1394 }
1395
1396 sub _is_case_sensitive { 0 }
1397
1398 # remove the dump dir from @INC on destruction
1399 sub DESTROY {
1400     my $self = shift;
1401
1402     @INC = grep $_ ne $self->dump_directory, @INC;
1403 }
1404
1405 =head2 monikers
1406
1407 Returns a hashref of loaded table to moniker mappings.  There will
1408 be two entries for each table, the original name and the "normalized"
1409 name, in the case that the two are different (such as databases
1410 that like uppercase table names, or preserve your original mixed-case
1411 definitions, or what-have-you).
1412
1413 =head2 classes
1414
1415 Returns a hashref of table to class mappings.  In some cases it will
1416 contain multiple entries per table for the original and normalized table
1417 names, as above in L</monikers>.
1418
1419 =head1 SEE ALSO
1420
1421 L<DBIx::Class::Schema::Loader>
1422
1423 =head1 AUTHOR
1424
1425 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
1426
1427 =head1 LICENSE
1428
1429 This library is free software; you can redistribute it and/or modify it under
1430 the same terms as Perl itself.
1431
1432 =cut
1433
1434 1;