33dff584a433a9dcfd37a644613519570ae82992
[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_10';
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     do $real_inc_path;
443     die $@ if $@;
444 }
445
446 =head2 load
447
448 Does the actual schema-construction work.
449
450 =cut
451
452 sub load {
453     my $self = shift;
454
455     $self->_load_tables($self->_tables_list);
456 }
457
458 =head2 rescan
459
460 Arguments: schema
461
462 Rescan the database for newly added tables.  Does
463 not process drops or changes.  Returns a list of
464 the newly added table monikers.
465
466 The schema argument should be the schema class
467 or object to be affected.  It should probably
468 be derived from the original schema_class used
469 during L</load>.
470
471 =cut
472
473 sub rescan {
474     my ($self, $schema) = @_;
475
476     $self->{schema} = $schema;
477     $self->_relbuilder->{schema} = $schema;
478
479     my @created;
480     my @current = $self->_tables_list;
481     foreach my $table ($self->_tables_list) {
482         if(!exists $self->{_tables}->{$table}) {
483             push(@created, $table);
484         }
485     }
486
487     my $loaded = $self->_load_tables(@created);
488
489     return map { $self->monikers->{$_} } @$loaded;
490 }
491
492 sub _relbuilder {
493     my ($self) = @_;
494
495     return if $self->{skip_relationships};
496
497     $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new(
498         $self->schema, $self->inflect_plural, $self->inflect_singular
499     );
500 }
501
502 sub _load_tables {
503     my ($self, @tables) = @_;
504
505     # First, use _tables_list with constraint and exclude
506     #  to get a list of tables to operate on
507
508     my $constraint   = $self->constraint;
509     my $exclude      = $self->exclude;
510
511     @tables = grep { /$constraint/ } @tables if $constraint;
512     @tables = grep { ! /$exclude/ } @tables if $exclude;
513
514     # Save the new tables to the tables list
515     foreach (@tables) {
516         $self->{_tables}->{$_} = 1;
517     }
518
519     $self->_make_src_class($_) for @tables;
520     $self->_setup_src_meta($_) for @tables;
521
522     if(!$self->skip_relationships) {
523         # The relationship loader needs a working schema
524         $self->{quiet} = 1;
525         local $self->{dump_directory} = $self->{temp_directory};
526         $self->_reload_classes(\@tables);
527         $self->_load_relationships($_) for @tables;
528         $self->{quiet} = 0;
529
530         # Remove that temp dir from INC so it doesn't get reloaded
531         @INC = grep { $_ ne $self->{dump_directory} } @INC;
532     }
533
534     $self->_load_external($_)
535         for map { $self->classes->{$_} } @tables;
536
537     # Reload without unloading first to preserve any symbols from external
538     # packages.
539     $self->_reload_classes(\@tables, 0);
540
541     # Drop temporary cache
542     delete $self->{_cache};
543
544     return \@tables;
545 }
546
547 sub _reload_classes {
548     my ($self, $tables, $unload) = @_;
549
550     my @tables = @$tables;
551     $unload = 1 unless defined $unload;
552
553     # so that we don't repeat custom sections
554     @INC = grep $_ ne $self->dump_directory, @INC;
555
556     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
557
558     unshift @INC, $self->dump_directory;
559     
560     my @to_register;
561     my %have_source = map { $_ => $self->schema->source($_) }
562         $self->schema->sources;
563
564     for my $table (@tables) {
565         my $moniker = $self->monikers->{$table};
566         my $class = $self->classes->{$table};
567         
568         {
569             no warnings 'redefine';
570             local *Class::C3::reinitialize = sub {};
571             use warnings;
572
573             Class::Unload->unload($class) if $unload;
574             my ($source, $resultset_class);
575             if (
576                 ($source = $have_source{$moniker})
577                 && ($resultset_class = $source->resultset_class)
578                 && ($resultset_class ne 'DBIx::Class::ResultSet')
579             ) {
580                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
581                 Class::Unload->unload($resultset_class) if $unload;
582                 $self->_reload_class($resultset_class) if $has_file;
583             }
584             $self->_reload_class($class);
585         }
586         push @to_register, [$moniker, $class];
587     }
588
589     Class::C3->reinitialize;
590     for (@to_register) {
591         $self->schema->register_class(@$_);
592     }
593 }
594
595 # We use this instead of ensure_class_loaded when there are package symbols we
596 # want to preserve.
597 sub _reload_class {
598     my ($self, $class) = @_;
599
600     my $class_path = $self->_class_path($class);
601     delete $INC{ $class_path };
602     eval "require $class;";
603 }
604
605 sub _get_dump_filename {
606     my ($self, $class) = (@_);
607
608     $class =~ s{::}{/}g;
609     return $self->dump_directory . q{/} . $class . q{.pm};
610 }
611
612 sub _ensure_dump_subdirs {
613     my ($self, $class) = (@_);
614
615     my @name_parts = split(/::/, $class);
616     pop @name_parts; # we don't care about the very last element,
617                      # which is a filename
618
619     my $dir = $self->dump_directory;
620     while (1) {
621         if(!-d $dir) {
622             mkdir($dir) or croak "mkdir('$dir') failed: $!";
623         }
624         last if !@name_parts;
625         $dir = File::Spec->catdir($dir, shift @name_parts);
626     }
627 }
628
629 sub _dump_to_dir {
630     my ($self, @classes) = @_;
631
632     my $schema_class = $self->schema_class;
633     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
634
635     my $target_dir = $self->dump_directory;
636     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
637         unless $self->{dynamic} or $self->{quiet};
638
639     my $schema_text =
640           qq|package $schema_class;\n\n|
641         . qq|# Created by DBIx::Class::Schema::Loader\n|
642         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
643         . qq|use strict;\nuse warnings;\n\n|
644         . qq|use base '$schema_base_class';\n\n|;
645
646     if ($self->use_namespaces) {
647         $schema_text .= qq|__PACKAGE__->load_namespaces|;
648         my $namespace_options;
649         for my $attr (qw(result_namespace
650                          resultset_namespace
651                          default_resultset_class)) {
652             if ($self->$attr) {
653                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
654             }
655         }
656         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
657         $schema_text .= qq|;\n|;
658     }
659     else {
660         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
661     }
662
663     $self->_write_classfile($schema_class, $schema_text);
664
665     my $result_base_class = $self->result_base_class || 'DBIx::Class';
666
667     foreach my $src_class (@classes) {
668         my $src_text = 
669               qq|package $src_class;\n\n|
670             . qq|# Created by DBIx::Class::Schema::Loader\n|
671             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
672             . qq|use strict;\nuse warnings;\n\n|
673             . qq|use base '$result_base_class';\n\n|;
674
675         $self->_write_classfile($src_class, $src_text);
676     }
677
678     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
679
680 }
681
682 sub _sig_comment {
683     my ($self, $version, $ts) = @_;
684     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
685          . qq| v| . $version
686          . q| @ | . $ts 
687          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
688 }
689
690 sub _write_classfile {
691     my ($self, $class, $text) = @_;
692
693     my $filename = $self->_get_dump_filename($class);
694     $self->_ensure_dump_subdirs($class);
695
696     if (-f $filename && $self->really_erase_my_files) {
697         warn "Deleting existing file '$filename' due to "
698             . "'really_erase_my_files' setting\n" unless $self->{quiet};
699         unlink($filename);
700     }    
701
702     my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
703
704     $text .= qq|$_\n|
705         for @{$self->{_dump_storage}->{$class} || []};
706
707     # Check and see if the dump is infact differnt
708
709     my $compare_to;
710     if ($old_md5) {
711       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
712       
713
714       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
715         return;
716       }
717     }
718
719     $text .= $self->_sig_comment(
720       $self->version_to_dump,
721       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
722     );
723
724     open(my $fh, '>', $filename)
725         or croak "Cannot open '$filename' for writing: $!";
726
727     # Write the top half and its MD5 sum
728     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
729
730     # Write out anything loaded via external partial class file in @INC
731     print $fh qq|$_\n|
732         for @{$self->{_ext_storage}->{$class} || []};
733
734     # Write out any custom content the user has added
735     print $fh $custom_content;
736
737     close($fh)
738         or croak "Error closing '$filename': $!";
739 }
740
741 sub _default_custom_content {
742     return qq|\n\n# You can replace this text with custom|
743          . qq| content, and it will be preserved on regeneration|
744          . qq|\n1;\n|;
745 }
746
747 sub _get_custom_content {
748     my ($self, $class, $filename) = @_;
749
750     return ($self->_default_custom_content) if ! -f $filename;
751
752     open(my $fh, '<', $filename)
753         or croak "Cannot open '$filename' for reading: $!";
754
755     my $mark_re = 
756         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
757
758     my $buffer = '';
759     my ($md5, $ts, $ver);
760     while(<$fh>) {
761         if(!$md5 && /$mark_re/) {
762             $md5 = $2;
763             my $line = $1;
764
765             # Pull out the previous version and timestamp
766             ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
767
768             $buffer .= $line;
769             croak "Checksum mismatch in '$filename'"
770                 if Digest::MD5::md5_base64($buffer) ne $md5;
771
772             $buffer = '';
773         }
774         else {
775             $buffer .= $_;
776         }
777     }
778
779     croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
780         . " it does not appear to have been generated by Loader"
781             if !$md5;
782
783     # Default custom content:
784     $buffer ||= $self->_default_custom_content;
785
786     return ($buffer, $md5, $ver, $ts);
787 }
788
789 sub _use {
790     my $self = shift;
791     my $target = shift;
792
793     foreach (@_) {
794         warn "$target: use $_;" if $self->debug;
795         $self->_raw_stmt($target, "use $_;");
796     }
797 }
798
799 sub _inject {
800     my $self = shift;
801     my $target = shift;
802     my $schema_class = $self->schema_class;
803
804     my $blist = join(q{ }, @_);
805     warn "$target: use base qw/ $blist /;" if $self->debug && @_;
806     $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
807 }
808
809 # Create class with applicable bases, setup monikers, etc
810 sub _make_src_class {
811     my ($self, $table) = @_;
812
813     my $schema       = $self->schema;
814     my $schema_class = $self->schema_class;
815
816     my $table_moniker = $self->_table2moniker($table);
817     my @result_namespace = ($schema_class);
818     if ($self->use_namespaces) {
819         my $result_namespace = $self->result_namespace || 'Result';
820         if ($result_namespace =~ /^\+(.*)/) {
821             # Fully qualified namespace
822             @result_namespace =  ($1)
823         }
824         else {
825             # Relative namespace
826             push @result_namespace, $result_namespace;
827         }
828     }
829     my $table_class = join(q{::}, @result_namespace, $table_moniker);
830
831     my $table_normalized = lc $table;
832     $self->classes->{$table} = $table_class;
833     $self->classes->{$table_normalized} = $table_class;
834     $self->monikers->{$table} = $table_moniker;
835     $self->monikers->{$table_normalized} = $table_moniker;
836
837     $self->_use   ($table_class, @{$self->additional_classes});
838     $self->_inject($table_class, @{$self->left_base_classes});
839
840     $self->_dbic_stmt($table_class, 'load_components', @{$self->components}, 'Core');
841
842     $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
843         if @{$self->resultset_components};
844     $self->_inject($table_class, @{$self->additional_base_classes});
845 }
846
847 # Set up metadata (cols, pks, etc)
848 sub _setup_src_meta {
849     my ($self, $table) = @_;
850
851     my $schema       = $self->schema;
852     my $schema_class = $self->schema_class;
853
854     my $table_class = $self->classes->{$table};
855     my $table_moniker = $self->monikers->{$table};
856
857     my $table_name = $table;
858     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
859
860     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
861         $table_name = \ $self->_quote_table_name($table_name);
862     }
863
864     $self->_dbic_stmt($table_class,'table',$table_name);
865
866     my $cols = $self->_table_columns($table);
867     my $col_info;
868     eval { $col_info = $self->_columns_info_for($table) };
869     if($@) {
870         $self->_dbic_stmt($table_class,'add_columns',@$cols);
871     }
872     else {
873         if ($self->_is_case_sensitive) {
874             for my $col (keys %$col_info) {
875                 $col_info->{$col}{accessor} = lc $col
876                     if $col ne lc($col);
877             }
878         } else {
879             $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
880         }
881
882         my $fks = $self->_table_fk_info($table);
883
884         for my $fkdef (@$fks) {
885             for my $col (@{ $fkdef->{local_columns} }) {
886                 $col_info->{$col}{is_foreign_key} = 1;
887             }
888         }
889         $self->_dbic_stmt(
890             $table_class,
891             'add_columns',
892             map { $_, ($col_info->{$_}||{}) } @$cols
893         );
894     }
895
896     my %uniq_tag; # used to eliminate duplicate uniqs
897
898     my $pks = $self->_table_pk_info($table) || [];
899     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
900           : carp("$table has no primary key");
901     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
902
903     my $uniqs = $self->_table_uniq_info($table) || [];
904     for (@$uniqs) {
905         my ($name, $cols) = @$_;
906         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
907         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
908     }
909
910 }
911
912 =head2 tables
913
914 Returns a sorted list of loaded tables, using the original database table
915 names.
916
917 =cut
918
919 sub tables {
920     my $self = shift;
921
922     return keys %{$self->_tables};
923 }
924
925 # Make a moniker from a table
926 sub _default_table2moniker {
927     my ($self, $table) = @_;
928
929     return join '', map ucfirst, split /[\W_]+/,
930         Lingua::EN::Inflect::Number::to_S(lc $table);
931 }
932
933 sub _table2moniker {
934     my ( $self, $table ) = @_;
935
936     my $moniker;
937
938     if( ref $self->moniker_map eq 'HASH' ) {
939         $moniker = $self->moniker_map->{$table};
940     }
941     elsif( ref $self->moniker_map eq 'CODE' ) {
942         $moniker = $self->moniker_map->($table);
943     }
944
945     $moniker ||= $self->_default_table2moniker($table);
946
947     return $moniker;
948 }
949
950 sub _load_relationships {
951     my ($self, $table) = @_;
952
953     my $tbl_fk_info = $self->_table_fk_info($table);
954     foreach my $fkdef (@$tbl_fk_info) {
955         $fkdef->{remote_source} =
956             $self->monikers->{delete $fkdef->{remote_table}};
957     }
958     my $tbl_uniq_info = $self->_table_uniq_info($table);
959
960     my $local_moniker = $self->monikers->{$table};
961     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
962
963     foreach my $src_class (sort keys %$rel_stmts) {
964         my $src_stmts = $rel_stmts->{$src_class};
965         foreach my $stmt (@$src_stmts) {
966             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
967         }
968     }
969 }
970
971 # Overload these in driver class:
972
973 # Returns an arrayref of column names
974 sub _table_columns { croak "ABSTRACT METHOD" }
975
976 # Returns arrayref of pk col names
977 sub _table_pk_info { croak "ABSTRACT METHOD" }
978
979 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
980 sub _table_uniq_info { croak "ABSTRACT METHOD" }
981
982 # Returns an arrayref of foreign key constraints, each
983 #   being a hashref with 3 keys:
984 #   local_columns (arrayref), remote_columns (arrayref), remote_table
985 sub _table_fk_info { croak "ABSTRACT METHOD" }
986
987 # Returns an array of lower case table names
988 sub _tables_list { croak "ABSTRACT METHOD" }
989
990 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
991 sub _dbic_stmt {
992     my $self = shift;
993     my $class = shift;
994     my $method = shift;
995
996     my $args = dump(@_);
997     $args = '(' . $args . ')' if @_ < 2;
998     my $stmt = $method . $args . q{;};
999
1000     warn qq|$class\->$stmt\n| if $self->debug;
1001     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1002 }
1003
1004 # Store a raw source line for a class (for dumping purposes)
1005 sub _raw_stmt {
1006     my ($self, $class, $stmt) = @_;
1007     push(@{$self->{_dump_storage}->{$class}}, $stmt);
1008 }
1009
1010 # Like above, but separately for the externally loaded stuff
1011 sub _ext_stmt {
1012     my ($self, $class, $stmt) = @_;
1013     push(@{$self->{_ext_storage}->{$class}}, $stmt);
1014 }
1015
1016 sub _quote_table_name {
1017     my ($self, $table) = @_;
1018
1019     my $qt = $self->schema->storage->sql_maker->quote_char;
1020
1021     return $table unless $qt;
1022
1023     if (ref $qt) {
1024         return $qt->[0] . $table . $qt->[1];
1025     }
1026
1027     return $qt . $table . $qt;
1028 }
1029
1030 sub _is_case_sensitive { 0 }
1031
1032 =head2 monikers
1033
1034 Returns a hashref of loaded table to moniker mappings.  There will
1035 be two entries for each table, the original name and the "normalized"
1036 name, in the case that the two are different (such as databases
1037 that like uppercase table names, or preserve your original mixed-case
1038 definitions, or what-have-you).
1039
1040 =head2 classes
1041
1042 Returns a hashref of table to class mappings.  In some cases it will
1043 contain multiple entries per table for the original and normalized table
1044 names, as above in L</monikers>.
1045
1046 =head1 SEE ALSO
1047
1048 L<DBIx::Class::Schema::Loader>
1049
1050 =head1 AUTHOR
1051
1052 See L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
1053
1054 =head1 LICENSE
1055
1056 This library is free software; you can redistribute it and/or modify it under
1057 the same terms as Perl itself.
1058
1059 =cut
1060
1061 1;