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