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