added warning and documentation for column accessor collisions, and the col_collision...
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
1 package DBIx::Class::Schema::Loader::Base;
2
3 use strict;
4 use warnings;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
6 use mro '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 Lingua::EN::Inflect::Phrase qw//;
16 use File::Temp qw//;
17 use Class::Unload;
18 use Class::Inspector ();
19 use Scalar::Util 'looks_like_number';
20 use File::Slurp 'slurp';
21 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_without_redefine_warnings/;
22 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
23 use Try::Tiny;
24 use DBIx::Class ();
25 use namespace::clean;
26
27 our $VERSION = '0.07002';
28
29 __PACKAGE__->mk_group_ro_accessors('simple', qw/
30                                 schema
31                                 schema_class
32
33                                 exclude
34                                 constraint
35                                 additional_classes
36                                 additional_base_classes
37                                 left_base_classes
38                                 components
39                                 resultset_components
40                                 skip_relationships
41                                 skip_load_external
42                                 moniker_map
43                                 custom_column_info
44                                 inflect_singular
45                                 inflect_plural
46                                 debug
47                                 dump_directory
48                                 dump_overwrite
49                                 really_erase_my_files
50                                 resultset_namespace
51                                 default_resultset_class
52                                 schema_base_class
53                                 result_base_class
54                                 use_moose
55                                 overwrite_modifications
56
57                                 relationship_attrs
58
59                                 db_schema
60                                 _tables
61                                 classes
62                                 _upgrading_classes
63                                 monikers
64                                 dynamic
65                                 naming
66                                 datetime_timezone
67                                 datetime_locale
68                                 config_file
69                                 loader_class
70                                 qualify_objects
71 /);
72
73
74 __PACKAGE__->mk_group_accessors('simple', qw/
75                                 version_to_dump
76                                 schema_version_to_dump
77                                 _upgrading_from
78                                 _upgrading_from_load_classes
79                                 _downgrading_to_load_classes
80                                 _rewriting_result_namespace
81                                 use_namespaces
82                                 result_namespace
83                                 generate_pod
84                                 pod_comment_mode
85                                 pod_comment_spillover_length
86                                 preserve_case
87                                 col_collision_map
88 /);
89
90 =head1 NAME
91
92 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
93
94 =head1 SYNOPSIS
95
96 See L<DBIx::Class::Schema::Loader>
97
98 =head1 DESCRIPTION
99
100 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
101 classes, and implements the common functionality between them.
102
103 =head1 CONSTRUCTOR OPTIONS
104
105 These constructor options are the base options for
106 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
107
108 =head2 skip_relationships
109
110 Skip setting up relationships.  The default is to attempt the loading
111 of relationships.
112
113 =head2 skip_load_external
114
115 Skip loading of other classes in @INC. The default is to merge all other classes
116 with the same name found in @INC into the schema file we are creating.
117
118 =head2 naming
119
120 Static schemas (ones dumped to disk) will, by default, use the new-style
121 relationship names and singularized Results, unless you're overwriting an
122 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
123 which case the backward compatible RelBuilder will be activated, and the
124 appropriate monikerization used.
125
126 Specifying
127
128     naming => 'current'
129
130 will disable the backward-compatible RelBuilder and use
131 the new-style relationship names along with singularized Results, even when
132 overwriting a dump made with an earlier version.
133
134 The option also takes a hashref:
135
136     naming => { relationships => 'v7', monikers => 'v7' }
137
138 The keys are:
139
140 =over 4
141
142 =item relationships
143
144 How to name relationship accessors.
145
146 =item monikers
147
148 How to name Result classes.
149
150 =item column_accessors
151
152 How to name column accessors in Result classes.
153
154 =back
155
156 The values can be:
157
158 =over 4
159
160 =item current
161
162 Latest style, whatever that happens to be.
163
164 =item v4
165
166 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
167
168 =item v5
169
170 Monikers singularized as whole words, C<might_have> relationships for FKs on
171 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
172
173 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
174 the v5 RelBuilder.
175
176 =item v6
177
178 All monikers and relationships are inflected using
179 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
180 from relationship names.
181
182 In general, there is very little difference between v5 and v6 schemas.
183
184 =item v7
185
186 This mode is identical to C<v6> mode, except that monikerization of CamelCase
187 table names is also done correctly.
188
189 CamelCase column names in case-preserving mode will also be handled correctly
190 for relationship name inflection. See L</preserve_case>.
191
192 In this mode, CamelCase L</column_accessors> are normalized based on case
193 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
194
195 If you don't have any CamelCase table or column names, you can upgrade without
196 breaking any of your code.
197
198 =back
199
200 Dynamic schemas will always default to the 0.04XXX relationship names and won't
201 singularize Results for backward compatibility, to activate the new RelBuilder
202 and singularization put this in your C<Schema.pm> file:
203
204     __PACKAGE__->naming('current');
205
206 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
207 next major version upgrade:
208
209     __PACKAGE__->naming('v7');
210
211 =head2 generate_pod
212
213 By default POD will be generated for columns and relationships, using database
214 metadata for the text if available and supported.
215
216 Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
217 supported for Postgres right now.
218
219 Set this to C<0> to turn off all POD generation.
220
221 =head2 pod_comment_mode
222
223 Controls where table comments appear in the generated POD. Smaller table
224 comments are appended to the C<NAME> section of the documentation, and larger
225 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
226 section to be generated with the comment always, only use C<NAME>, or choose
227 the length threshold at which the comment is forced into the description.
228
229 =over 4
230
231 =item name
232
233 Use C<NAME> section only.
234
235 =item description
236
237 Force C<DESCRIPTION> always.
238
239 =item auto
240
241 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
242 default.
243
244 =back
245
246 =head2 pod_comment_spillover_length
247
248 When pod_comment_mode is set to C<auto>, this is the length of the comment at
249 which it will be forced into a separate description section.
250
251 The default is C<60>
252
253 =head2 relationship_attrs
254
255 Hashref of attributes to pass to each generated relationship, listed
256 by type.  Also supports relationship type 'all', containing options to
257 pass to all generated relationships.  Attributes set for more specific
258 relationship types override those set in 'all'.
259
260 For example:
261
262   relationship_attrs => {
263     belongs_to => { is_deferrable => 0 },
264   },
265
266 use this to turn off DEFERRABLE on your foreign key constraints.
267
268 =head2 debug
269
270 If set to true, each constructive L<DBIx::Class> statement the loader
271 decides to execute will be C<warn>-ed before execution.
272
273 =head2 db_schema
274
275 Set the name of the schema to load (schema in the sense that your database
276 vendor means it).  Does not currently support loading more than one schema
277 name.
278
279 =head2 constraint
280
281 Only load tables matching regex.  Best specified as a qr// regex.
282
283 =head2 exclude
284
285 Exclude tables matching regex.  Best specified as a qr// regex.
286
287 =head2 moniker_map
288
289 Overrides the default table name to moniker translation.  Can be either
290 a hashref of table keys and moniker values, or a coderef for a translator
291 function taking a single scalar table name argument and returning
292 a scalar moniker.  If the hash entry does not exist, or the function
293 returns a false value, the code falls back to default behavior
294 for that table name.
295
296 The default behavior is to split on case transition and non-alphanumeric
297 boundaries, singularize the resulting phrase, then join the titlecased words
298 together. Examples:
299
300     Table Name       | Moniker Name
301     ---------------------------------
302     luser            | Luser
303     luser_group      | LuserGroup
304     luser-opts       | LuserOpt
305     stations_visited | StationVisited
306     routeChange      | RouteChange
307
308 =head2 inflect_plural
309
310 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
311 if hash key does not exist or coderef returns false), but acts as a map
312 for pluralizing relationship names.  The default behavior is to utilize
313 L<Lingua::EN::Inflect::Number/to_PL>.
314
315 =head2 inflect_singular
316
317 As L</inflect_plural> above, but for singularizing relationship names.
318 Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
319
320 =head2 schema_base_class
321
322 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
323
324 =head2 result_base_class
325
326 Base class for your table classes (aka result classes). Defaults to
327 'DBIx::Class::Core'.
328
329 =head2 additional_base_classes
330
331 List of additional base classes all of your table classes will use.
332
333 =head2 left_base_classes
334
335 List of additional base classes all of your table classes will use
336 that need to be leftmost.
337
338 =head2 additional_classes
339
340 List of additional classes which all of your table classes will use.
341
342 =head2 components
343
344 List of additional components to be loaded into all of your table
345 classes.  A good example would be
346 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
347
348 =head2 resultset_components
349
350 List of additional ResultSet components to be loaded into your table
351 classes.  A good example would be C<AlwaysRS>.  Component
352 C<ResultSetManager> will be automatically added to the above
353 C<components> list if this option is set.
354
355 =head2 use_namespaces
356
357 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
358 a C<0>.
359
360 Generate result class names suitable for
361 L<DBIx::Class::Schema/load_namespaces> and call that instead of
362 L<DBIx::Class::Schema/load_classes>. When using this option you can also
363 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
364 C<resultset_namespace>, C<default_resultset_class>), and they will be added
365 to the call (and the generated result class names adjusted appropriately).
366
367 =head2 dump_directory
368
369 This option is designed to be a tool to help you transition from this
370 loader to a manually-defined schema when you decide it's time to do so.
371
372 The value of this option is a perl libdir pathname.  Within
373 that directory this module will create a baseline manual
374 L<DBIx::Class::Schema> module set, based on what it creates at runtime
375 in memory.
376
377 The created schema class will have the same classname as the one on
378 which you are setting this option (and the ResultSource classes will be
379 based on this name as well).
380
381 Normally you wouldn't hard-code this setting in your schema class, as it
382 is meant for one-time manual usage.
383
384 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
385 recommended way to access this functionality.
386
387 =head2 dump_overwrite
388
389 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
390 the same thing as the old C<dump_overwrite> setting from previous releases.
391
392 =head2 really_erase_my_files
393
394 Default false.  If true, Loader will unconditionally delete any existing
395 files before creating the new ones from scratch when dumping a schema to disk.
396
397 The default behavior is instead to only replace the top portion of the
398 file, up to and including the final stanza which contains
399 C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
400 leaving any customizations you placed after that as they were.
401
402 When C<really_erase_my_files> is not set, if the output file already exists,
403 but the aforementioned final stanza is not found, or the checksum
404 contained there does not match the generated contents, Loader will
405 croak and not touch the file.
406
407 You should really be using version control on your schema classes (and all
408 of the rest of your code for that matter).  Don't blame me if a bug in this
409 code wipes something out when it shouldn't have, you've been warned.
410
411 =head2 overwrite_modifications
412
413 Default false.  If false, when updating existing files, Loader will
414 refuse to modify any Loader-generated code that has been modified
415 since its last run (as determined by the checksum Loader put in its
416 comment lines).
417
418 If true, Loader will discard any manual modifications that have been
419 made to Loader-generated code.
420
421 Again, you should be using version control on your schema classes.  Be
422 careful with this option.
423
424 =head2 custom_column_info
425
426 Hook for adding extra attributes to the
427 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
428
429 Must be a coderef that returns a hashref with the extra attributes.
430
431 Receives the table name, column name and column_info.
432
433 For example:
434
435   custom_column_info => sub {
436       my ($table_name, $column_name, $column_info) = @_;
437
438       if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
439           return { is_snoopy => 1 };
440       }
441   },
442
443 This attribute can also be used to set C<inflate_datetime> on a non-datetime
444 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
445
446 =head2 datetime_timezone
447
448 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
449 columns with the DATE/DATETIME/TIMESTAMP data_types.
450
451 =head2 datetime_locale
452
453 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
454 columns with the DATE/DATETIME/TIMESTAMP data_types.
455
456 =head2 config_file
457
458 File in Perl format, which should return a HASH reference, from which to read
459 loader options.
460
461 =head2 preserve_case
462
463 Usually column names are lowercased, to make them easier to work with in
464 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
465 supports it.
466
467 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
468 case-sensitive collation will turn this option on unconditionally.
469
470 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
471 setting this option.
472
473 =head2 qualify_objects
474
475 Set to true to prepend the L</db_schema> to table names for C<<
476 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
477
478 =head2 use_moose
479
480 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
481 L<namespace::autoclean>. The default content after the md5 sum also makes the
482 classes immutable.
483
484 It is safe to upgrade your existing Schema to this option.
485
486 =head2 col_collision_map
487
488 This option controls how accessors for column names which collide with perl
489 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
490
491 This option takes either a single L<perlfunc/sprintf> format or a hashref of
492 strings which are compiled to regular expressions that map to
493 L<perlfunc/sprintf> formats.
494
495 Examples:
496
497     col_collision_map => 'column_%s'
498
499     col_collision_map => { '(.*)' => 'column_%s' }
500
501     col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
502
503 =head1 METHODS
504
505 None of these methods are intended for direct invocation by regular
506 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
507 L<DBIx::Class::Schema::Loader>.
508
509 =cut
510
511 my $CURRENT_V = 'v7';
512
513 my @CLASS_ARGS = qw(
514     schema_base_class result_base_class additional_base_classes
515     left_base_classes additional_classes components resultset_components
516 );
517
518 # ensure that a peice of object data is a valid arrayref, creating
519 # an empty one or encapsulating whatever's there.
520 sub _ensure_arrayref {
521     my $self = shift;
522
523     foreach (@_) {
524         $self->{$_} ||= [];
525         $self->{$_} = [ $self->{$_} ]
526             unless ref $self->{$_} eq 'ARRAY';
527     }
528 }
529
530 =head2 new
531
532 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
533 by L<DBIx::Class::Schema::Loader>.
534
535 =cut
536
537 sub new {
538     my ( $class, %args ) = @_;
539
540     my $self = { %args };
541
542     # don't lose undef options
543     for (values %$self) {
544         $_ = 0 unless defined $_;
545     }
546
547     bless $self => $class;
548
549     if (my $config_file = $self->config_file) {
550         my $config_opts = do $config_file;
551
552         croak "Error reading config from $config_file: $@" if $@;
553
554         croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
555
556         while (my ($k, $v) = each %$config_opts) {
557             $self->{$k} = $v unless exists $self->{$k};
558         }
559     }
560
561     $self->_ensure_arrayref(qw/additional_classes
562                                additional_base_classes
563                                left_base_classes
564                                components
565                                resultset_components
566                               /);
567
568     $self->_validate_class_args;
569
570     if ($self->use_moose) {
571         if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
572             die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
573                 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
574         }
575     }
576
577     push(@{$self->{components}}, 'ResultSetManager')
578         if @{$self->{resultset_components}};
579
580     $self->{monikers} = {};
581     $self->{classes} = {};
582     $self->{_upgrading_classes} = {};
583
584     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
585     $self->{schema} ||= $self->{schema_class};
586
587     croak "dump_overwrite is deprecated.  Please read the"
588         . " DBIx::Class::Schema::Loader::Base documentation"
589             if $self->{dump_overwrite};
590
591     $self->{dynamic} = ! $self->{dump_directory};
592     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
593                                                      TMPDIR  => 1,
594                                                      CLEANUP => 1,
595                                                    );
596
597     $self->{dump_directory} ||= $self->{temp_directory};
598
599     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
600     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
601
602     if ((not ref $self->naming) && defined $self->naming) {
603         my $naming_ver = $self->naming;
604         $self->{naming} = {
605             relationships => $naming_ver,
606             monikers => $naming_ver,
607             column_accessors => $naming_ver,
608         };
609     }
610
611     if ($self->naming) {
612         for (values %{ $self->naming }) {
613             $_ = $CURRENT_V if $_ eq 'current';
614         }
615     }
616     $self->{naming} ||= {};
617
618     if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
619         croak 'custom_column_info must be a CODE ref';
620     }
621
622     $self->_check_back_compat;
623
624     $self->use_namespaces(1) unless defined $self->use_namespaces;
625     $self->generate_pod(1)   unless defined $self->generate_pod;
626     $self->pod_comment_mode('auto')         unless defined $self->pod_comment_mode;
627     $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
628
629     if (my $col_collision_map = $self->col_collision_map) {
630         if (my $reftype = ref $col_collision_map) {
631             if ($reftype ne 'HASH') {
632                 croak "Invalid type $reftype for option 'col_collision_map'";
633             }
634         }
635         else {
636             $self->col_collision_map({ '(.*)' => $col_collision_map });
637         }
638     }
639
640     $self;
641 }
642
643 sub _check_back_compat {
644     my ($self) = @_;
645
646 # dynamic schemas will always be in 0.04006 mode, unless overridden
647     if ($self->dynamic) {
648 # just in case, though no one is likely to dump a dynamic schema
649         $self->schema_version_to_dump('0.04006');
650
651         if (not %{ $self->naming }) {
652             warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
653
654 Dynamic schema detected, will run in 0.04006 mode.
655
656 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
657 to disable this warning.
658
659 Also consider setting 'use_namespaces => 1' if/when upgrading.
660
661 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
662 details.
663 EOF
664         }
665         else {
666             $self->_upgrading_from('v4');
667         }
668
669         $self->naming->{relationships} ||= 'v4';
670         $self->naming->{monikers}      ||= 'v4';
671
672         if ($self->use_namespaces) {
673             $self->_upgrading_from_load_classes(1);
674         }
675         else {
676             $self->use_namespaces(0);
677         }
678
679         return;
680     }
681
682 # otherwise check if we need backcompat mode for a static schema
683     my $filename = $self->_get_dump_filename($self->schema_class);
684     return unless -e $filename;
685
686     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
687       $self->_parse_generated_file($filename);
688
689     return unless $old_ver;
690
691     # determine if the existing schema was dumped with use_moose => 1
692     if (! defined $self->use_moose) {
693         $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
694     }
695
696     my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
697     my $result_namespace = do { ($old_gen =~ /result_namespace => '([^']+)'/) ? $1 : '' };
698
699     if ($load_classes && (not defined $self->use_namespaces)) {
700         warn <<"EOF"  unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
701
702 'load_classes;' static schema detected, turning off 'use_namespaces'.
703
704 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
705 variable to disable this warning.
706
707 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
708 details.
709 EOF
710         $self->use_namespaces(0);
711     }
712     elsif ($load_classes && $self->use_namespaces) {
713         $self->_upgrading_from_load_classes(1);
714     }
715     elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
716         $self->_downgrading_to_load_classes(
717             $result_namespace || 'Result'
718         );
719     }
720     elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
721         if (not $self->result_namespace) {
722             $self->result_namespace($result_namespace || 'Result');
723         }
724         elsif ($result_namespace ne $self->result_namespace) {
725             $self->_rewriting_result_namespace(
726                 $result_namespace || 'Result'
727             );
728         }
729     }
730
731     # XXX when we go past .0 this will need fixing
732     my ($v) = $old_ver =~ /([1-9])/;
733     $v = "v$v";
734
735     return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
736
737     if (not %{ $self->naming }) {
738         warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
739
740 Version $old_ver static schema detected, turning on backcompat mode.
741
742 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
743 to disable this warning.
744
745 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
746
747 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
748 from version 0.04006.
749 EOF
750
751         $self->naming->{relationships}    ||= $v;
752         $self->naming->{monikers}         ||= $v;
753         $self->naming->{column_accessors} ||= $v;
754
755         $self->schema_version_to_dump($old_ver);
756     }
757     else {
758         $self->_upgrading_from($v);
759     }
760 }
761
762 sub _validate_class_args {
763     my $self = shift;
764     my $args = shift;
765
766     foreach my $k (@CLASS_ARGS) {
767         next unless $self->$k;
768
769         my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
770         foreach my $c (@classes) {
771             # components default to being under the DBIx::Class namespace unless they
772             # are preceeded with a '+'
773             if ( $k =~ m/components$/ && $c !~ s/^\+// ) {
774                 $c = 'DBIx::Class::' . $c;
775             }
776
777             # 1 == installed, 0 == not installed, undef == invalid classname
778             my $installed = Class::Inspector->installed($c);
779             if ( defined($installed) ) {
780                 if ( $installed == 0 ) {
781                     croak qq/$c, as specified in the loader option "$k", is not installed/;
782                 }
783             } else {
784                 croak qq/$c, as specified in the loader option "$k", is an invalid class name/;
785             }
786         }
787     }
788 }
789
790 sub _find_file_in_inc {
791     my ($self, $file) = @_;
792
793     foreach my $prefix (@INC) {
794         my $fullpath = File::Spec->catfile($prefix, $file);
795         return $fullpath if -f $fullpath
796             # abs_path throws on Windows for nonexistant files
797             and eval { Cwd::abs_path($fullpath) } ne
798                (eval { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) } || '');
799     }
800
801     return;
802 }
803
804 sub _class_path {
805     my ($self, $class) = @_;
806
807     my $class_path = $class;
808     $class_path =~ s{::}{/}g;
809     $class_path .= '.pm';
810
811     return $class_path;
812 }
813
814 sub _find_class_in_inc {
815     my ($self, $class) = @_;
816
817     return $self->_find_file_in_inc($self->_class_path($class));
818 }
819
820 sub _rewriting {
821     my $self = shift;
822
823     return $self->_upgrading_from
824         || $self->_upgrading_from_load_classes
825         || $self->_downgrading_to_load_classes
826         || $self->_rewriting_result_namespace
827     ;
828 }
829
830 sub _rewrite_old_classnames {
831     my ($self, $code) = @_;
832
833     return $code unless $self->_rewriting;
834
835     my %old_classes = reverse %{ $self->_upgrading_classes };
836
837     my $re = join '|', keys %old_classes;
838     $re = qr/\b($re)\b/;
839
840     $code =~ s/$re/$old_classes{$1} || $1/eg;
841
842     return $code;
843 }
844
845 sub _load_external {
846     my ($self, $class) = @_;
847
848     return if $self->{skip_load_external};
849
850     # so that we don't load our own classes, under any circumstances
851     local *INC = [ grep $_ ne $self->dump_directory, @INC ];
852
853     my $real_inc_path = $self->_find_class_in_inc($class);
854
855     my $old_class = $self->_upgrading_classes->{$class}
856         if $self->_rewriting;
857
858     my $old_real_inc_path = $self->_find_class_in_inc($old_class)
859         if $old_class && $old_class ne $class;
860
861     return unless $real_inc_path || $old_real_inc_path;
862
863     if ($real_inc_path) {
864         # If we make it to here, we loaded an external definition
865         warn qq/# Loaded external class definition for '$class'\n/
866             if $self->debug;
867
868         open(my $fh, '<', $real_inc_path)
869             or croak "Failed to open '$real_inc_path' for reading: $!";
870         my $code = do { local $/; <$fh> };
871         close($fh)
872             or croak "Failed to close $real_inc_path: $!";
873         $code = $self->_rewrite_old_classnames($code);
874
875         if ($self->dynamic) { # load the class too
876             eval_without_redefine_warnings($code);
877         }
878
879         $self->_ext_stmt($class,
880           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
881          .qq|# They are now part of the custom portion of this file\n|
882          .qq|# for you to hand-edit.  If you do not either delete\n|
883          .qq|# this section or remove that file from \@INC, this section\n|
884          .qq|# will be repeated redundantly when you re-create this\n|
885          .qq|# file again via Loader!  See skip_load_external to disable\n|
886          .qq|# this feature.\n|
887         );
888         chomp $code;
889         $self->_ext_stmt($class, $code);
890         $self->_ext_stmt($class,
891             qq|# End of lines loaded from '$real_inc_path' |
892         );
893     }
894
895     if ($old_real_inc_path) {
896         my $code = slurp $old_real_inc_path;
897
898         $self->_ext_stmt($class, <<"EOF");
899
900 # These lines were loaded from '$old_real_inc_path',
901 # based on the Result class name that would have been created by an older
902 # version of the Loader. For a static schema, this happens only once during
903 # upgrade. See skip_load_external to disable this feature.
904 EOF
905
906         $code = $self->_rewrite_old_classnames($code);
907
908         if ($self->dynamic) {
909             warn <<"EOF";
910
911 Detected external content in '$old_real_inc_path', a class name that would have
912 been used by an older version of the Loader.
913
914 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
915 new name of the Result.
916 EOF
917             eval_without_redefine_warnings($code);
918         }
919
920         chomp $code;
921         $self->_ext_stmt($class, $code);
922         $self->_ext_stmt($class,
923             qq|# End of lines loaded from '$old_real_inc_path' |
924         );
925     }
926 }
927
928 =head2 load
929
930 Does the actual schema-construction work.
931
932 =cut
933
934 sub load {
935     my $self = shift;
936
937     $self->_load_tables(
938         $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
939     );
940 }
941
942 =head2 rescan
943
944 Arguments: schema
945
946 Rescan the database for changes. Returns a list of the newly added table
947 monikers.
948
949 The schema argument should be the schema class or object to be affected.  It
950 should probably be derived from the original schema_class used during L</load>.
951
952 =cut
953
954 sub rescan {
955     my ($self, $schema) = @_;
956
957     $self->{schema} = $schema;
958     $self->_relbuilder->{schema} = $schema;
959
960     my @created;
961     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
962
963     foreach my $table (@current) {
964         if(!exists $self->{_tables}->{$table}) {
965             push(@created, $table);
966         }
967     }
968
969     my %current;
970     @current{@current} = ();
971     foreach my $table (keys %{ $self->{_tables} }) {
972         if (not exists $current{$table}) {
973             $self->_unregister_source_for_table($table);
974         }
975     }
976
977     delete $self->{_dump_storage};
978     delete $self->{_relations_started};
979
980     my $loaded = $self->_load_tables(@current);
981
982     return map { $self->monikers->{$_} } @created;
983 }
984
985 sub _relbuilder {
986     my ($self) = @_;
987
988     return if $self->{skip_relationships};
989
990     return $self->{relbuilder} ||= do {
991
992         no warnings 'uninitialized';
993         my $relbuilder_suff =
994             {qw{
995                 v4  ::Compat::v0_040
996                 v5  ::Compat::v0_05
997                 v6  ::Compat::v0_06
998             }}
999             ->{ $self->naming->{relationships}};
1000
1001         my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1002         eval "require $relbuilder_class"; die $@ if $@;
1003         $relbuilder_class->new( $self );
1004
1005     };
1006 }
1007
1008 sub _load_tables {
1009     my ($self, @tables) = @_;
1010
1011     # Save the new tables to the tables list
1012     foreach (@tables) {
1013         $self->{_tables}->{$_} = 1;
1014     }
1015
1016     $self->_make_src_class($_) for @tables;
1017
1018     # sanity-check for moniker clashes
1019     my $inverse_moniker_idx;
1020     for (keys %{$self->monikers}) {
1021       push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1022     }
1023
1024     my @clashes;
1025     for (keys %$inverse_moniker_idx) {
1026       my $tables = $inverse_moniker_idx->{$_};
1027       if (@$tables > 1) {
1028         push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1029           join (', ', map { "'$_'" } @$tables),
1030           $_,
1031         );
1032       }
1033     }
1034
1035     if (@clashes) {
1036       die   'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1037           . 'Either change the naming style, or supply an explicit moniker_map: '
1038           . join ('; ', @clashes)
1039           . "\n"
1040       ;
1041     }
1042
1043
1044     $self->_setup_src_meta($_) for @tables;
1045
1046     if(!$self->skip_relationships) {
1047         # The relationship loader needs a working schema
1048         $self->{quiet} = 1;
1049         local $self->{dump_directory} = $self->{temp_directory};
1050         $self->_reload_classes(\@tables);
1051         $self->_load_relationships($_) for @tables;
1052         $self->{quiet} = 0;
1053
1054         # Remove that temp dir from INC so it doesn't get reloaded
1055         @INC = grep $_ ne $self->dump_directory, @INC;
1056     }
1057
1058     $self->_load_external($_)
1059         for map { $self->classes->{$_} } @tables;
1060
1061     # Reload without unloading first to preserve any symbols from external
1062     # packages.
1063     $self->_reload_classes(\@tables, 0);
1064
1065     # Drop temporary cache
1066     delete $self->{_cache};
1067
1068     return \@tables;
1069 }
1070
1071 sub _reload_classes {
1072     my ($self, $tables, $unload) = @_;
1073
1074     my @tables = @$tables;
1075     $unload = 1 unless defined $unload;
1076
1077     # so that we don't repeat custom sections
1078     @INC = grep $_ ne $self->dump_directory, @INC;
1079
1080     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1081
1082     unshift @INC, $self->dump_directory;
1083     
1084     my @to_register;
1085     my %have_source = map { $_ => $self->schema->source($_) }
1086         $self->schema->sources;
1087
1088     for my $table (@tables) {
1089         my $moniker = $self->monikers->{$table};
1090         my $class = $self->classes->{$table};
1091         
1092         {
1093             no warnings 'redefine';
1094             local *Class::C3::reinitialize = sub {};  # to speed things up, reinitialized below
1095             use warnings;
1096
1097             if (my $mc = $self->_moose_metaclass($class)) {
1098                 $mc->make_mutable;
1099             }
1100             Class::Unload->unload($class) if $unload;
1101             my ($source, $resultset_class);
1102             if (
1103                 ($source = $have_source{$moniker})
1104                 && ($resultset_class = $source->resultset_class)
1105                 && ($resultset_class ne 'DBIx::Class::ResultSet')
1106             ) {
1107                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1108                 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1109                     $mc->make_mutable;
1110                 }
1111                 Class::Unload->unload($resultset_class) if $unload;
1112                 $self->_reload_class($resultset_class) if $has_file;
1113             }
1114             $self->_reload_class($class);
1115         }
1116         push @to_register, [$moniker, $class];
1117     }
1118
1119     Class::C3->reinitialize;
1120     for (@to_register) {
1121         $self->schema->register_class(@$_);
1122     }
1123 }
1124
1125 sub _moose_metaclass {
1126   return undef unless $INC{'Class/MOP.pm'};   # if CMOP is not loaded the class could not have loaded in the 1st place
1127
1128   my $mc = Class::MOP::class_of($_[1])
1129     or return undef;
1130
1131   return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1132 }
1133
1134 # We use this instead of ensure_class_loaded when there are package symbols we
1135 # want to preserve.
1136 sub _reload_class {
1137     my ($self, $class) = @_;
1138
1139     my $class_path = $self->_class_path($class);
1140     delete $INC{ $class_path };
1141
1142 # kill redefined warnings
1143     eval {
1144         eval_without_redefine_warnings ("require $class");
1145     };
1146     die "Failed to reload class $class: $@" if $@;
1147 }
1148
1149 sub _get_dump_filename {
1150     my ($self, $class) = (@_);
1151
1152     $class =~ s{::}{/}g;
1153     return $self->dump_directory . q{/} . $class . q{.pm};
1154 }
1155
1156 sub _ensure_dump_subdirs {
1157     my ($self, $class) = (@_);
1158
1159     my @name_parts = split(/::/, $class);
1160     pop @name_parts; # we don't care about the very last element,
1161                      # which is a filename
1162
1163     my $dir = $self->dump_directory;
1164     while (1) {
1165         if(!-d $dir) {
1166             mkdir($dir) or croak "mkdir('$dir') failed: $!";
1167         }
1168         last if !@name_parts;
1169         $dir = File::Spec->catdir($dir, shift @name_parts);
1170     }
1171 }
1172
1173 sub _dump_to_dir {
1174     my ($self, @classes) = @_;
1175
1176     my $schema_class = $self->schema_class;
1177     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1178
1179     my $target_dir = $self->dump_directory;
1180     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1181         unless $self->{dynamic} or $self->{quiet};
1182
1183     my $schema_text =
1184           qq|package $schema_class;\n\n|
1185         . qq|# Created by DBIx::Class::Schema::Loader\n|
1186         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1187         . qq|use strict;\nuse warnings;\n\n|;
1188     if ($self->use_moose) {
1189         $schema_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1190     }
1191     else {
1192         $schema_text .= qq|use base '$schema_base_class';\n\n|;
1193     }
1194
1195     if ($self->use_namespaces) {
1196         $schema_text .= qq|__PACKAGE__->load_namespaces|;
1197         my $namespace_options;
1198
1199         my @attr = qw/resultset_namespace default_resultset_class/;
1200
1201         unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1202
1203         for my $attr (@attr) {
1204             if ($self->$attr) {
1205                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
1206             }
1207         }
1208         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1209         $schema_text .= qq|;\n|;
1210     }
1211     else {
1212         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1213     }
1214
1215     {
1216         local $self->{version_to_dump} = $self->schema_version_to_dump;
1217         $self->_write_classfile($schema_class, $schema_text, 1);
1218     }
1219
1220     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1221
1222     foreach my $src_class (@classes) {
1223         my $src_text = 
1224               qq|package $src_class;\n\n|
1225             . qq|# Created by DBIx::Class::Schema::Loader\n|
1226             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1227             . qq|use strict;\nuse warnings;\n\n|;
1228         if ($self->use_moose) {
1229             $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1230
1231             # these options 'use base' which is compile time
1232             if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1233                 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1234             }
1235             else {
1236                 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1237             }
1238         }
1239         else {
1240              $src_text .= qq|use base '$result_base_class';\n\n|;
1241         }
1242         $self->_write_classfile($src_class, $src_text);
1243     }
1244
1245     # remove Result dir if downgrading from use_namespaces, and there are no
1246     # files left.
1247     if (my $result_ns = $self->_downgrading_to_load_classes
1248                         || $self->_rewriting_result_namespace) {
1249         my $result_namespace = $self->_result_namespace(
1250             $schema_class,
1251             $result_ns,
1252         );
1253
1254         (my $result_dir = $result_namespace) =~ s{::}{/}g;
1255         $result_dir = $self->dump_directory . '/' . $result_dir;
1256
1257         unless (my @files = glob "$result_dir/*") {
1258             rmdir $result_dir;
1259         }
1260     }
1261
1262     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1263
1264 }
1265
1266 sub _sig_comment {
1267     my ($self, $version, $ts) = @_;
1268     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1269          . qq| v| . $version
1270          . q| @ | . $ts 
1271          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1272 }
1273
1274 sub _write_classfile {
1275     my ($self, $class, $text, $is_schema) = @_;
1276
1277     my $filename = $self->_get_dump_filename($class);
1278     $self->_ensure_dump_subdirs($class);
1279
1280     if (-f $filename && $self->really_erase_my_files) {
1281         warn "Deleting existing file '$filename' due to "
1282             . "'really_erase_my_files' setting\n" unless $self->{quiet};
1283         unlink($filename);
1284     }
1285
1286     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1287         = $self->_parse_generated_file($filename);
1288
1289     if (! $old_gen && -f $filename) {
1290         croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1291             . " it does not appear to have been generated by Loader"
1292     }
1293
1294     my $custom_content = $old_custom || '';
1295
1296     # prepend extra custom content from a *renamed* class (singularization effect)
1297     if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1298         my $old_filename = $self->_get_dump_filename($renamed_class);
1299
1300         if (-f $old_filename) {
1301             my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1302
1303             $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1304
1305             $custom_content = join ("\n", '', $extra_custom, $custom_content)
1306                 if $extra_custom;
1307
1308             unlink $old_filename;
1309         }
1310     }
1311
1312     $custom_content ||= $self->_default_custom_content;
1313
1314     # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1315     # If there is already custom content, which does not have the Moose content, add it.
1316     if ($self->use_moose) {
1317
1318         my $non_moose_custom_content = do {
1319             local $self->{use_moose} = 0;
1320             $self->_default_custom_content;
1321         };
1322
1323         if ($custom_content eq $non_moose_custom_content) {
1324             $custom_content = $self->_default_custom_content;
1325         }
1326         elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content]}\E/) {
1327             $custom_content .= $self->_default_custom_content;
1328         }
1329     }
1330     elsif (defined $self->use_moose && $old_gen) {
1331         croak 'It is not possible to "downgrade" a schema that was loaded with use_moose => 1 to use_moose => 0, due to differing custom content'
1332             if $old_gen =~ /use \s+ MooseX?\b/x;
1333     }
1334
1335     $custom_content = $self->_rewrite_old_classnames($custom_content);
1336
1337     $text .= qq|$_\n|
1338         for @{$self->{_dump_storage}->{$class} || []};
1339
1340     # Check and see if the dump is infact differnt
1341
1342     my $compare_to;
1343     if ($old_md5) {
1344       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1345       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
1346         return unless $self->_upgrading_from && $is_schema;
1347       }
1348     }
1349
1350     $text .= $self->_sig_comment(
1351       $self->version_to_dump,
1352       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1353     );
1354
1355     open(my $fh, '>', $filename)
1356         or croak "Cannot open '$filename' for writing: $!";
1357
1358     # Write the top half and its MD5 sum
1359     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1360
1361     # Write out anything loaded via external partial class file in @INC
1362     print $fh qq|$_\n|
1363         for @{$self->{_ext_storage}->{$class} || []};
1364
1365     # Write out any custom content the user has added
1366     print $fh $custom_content;
1367
1368     close($fh)
1369         or croak "Error closing '$filename': $!";
1370 }
1371
1372 sub _default_moose_custom_content {
1373     return qq|\n__PACKAGE__->meta->make_immutable;|;
1374 }
1375
1376 sub _default_custom_content {
1377     my $self = shift;
1378     my $default = qq|\n\n# You can replace this text with custom|
1379          . qq| code or comments, and it will be preserved on regeneration|;
1380     if ($self->use_moose) {
1381         $default .= $self->_default_moose_custom_content;
1382     }
1383     $default .= qq|\n1;\n|;
1384     return $default;
1385 }
1386
1387 sub _parse_generated_file {
1388     my ($self, $fn) = @_;
1389
1390     return unless -f $fn;
1391
1392     open(my $fh, '<', $fn)
1393         or croak "Cannot open '$fn' for reading: $!";
1394
1395     my $mark_re =
1396         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1397
1398     my ($md5, $ts, $ver, $gen);
1399     while(<$fh>) {
1400         if(/$mark_re/) {
1401             my $pre_md5 = $1;
1402             $md5 = $2;
1403
1404             # Pull out the version and timestamp from the line above
1405             ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
1406
1407             $gen .= $pre_md5;
1408             croak "Checksum mismatch in '$fn', the auto-generated part of the file has been modified outside of this loader.  Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1409                 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
1410
1411             last;
1412         }
1413         else {
1414             $gen .= $_;
1415         }
1416     }
1417
1418     my $custom = do { local $/; <$fh> }
1419         if $md5;
1420
1421     close ($fh);
1422
1423     return ($gen, $md5, $ver, $ts, $custom);
1424 }
1425
1426 sub _use {
1427     my $self = shift;
1428     my $target = shift;
1429
1430     foreach (@_) {
1431         warn "$target: use $_;" if $self->debug;
1432         $self->_raw_stmt($target, "use $_;");
1433     }
1434 }
1435
1436 sub _inject {
1437     my $self = shift;
1438     my $target = shift;
1439
1440     my $blist = join(q{ }, @_);
1441
1442     return unless $blist;
1443
1444     warn "$target: use base qw/$blist/;" if $self->debug;
1445     $self->_raw_stmt($target, "use base qw/$blist/;");
1446 }
1447
1448 sub _result_namespace {
1449     my ($self, $schema_class, $ns) = @_;
1450     my @result_namespace;
1451
1452     if ($ns =~ /^\+(.*)/) {
1453         # Fully qualified namespace
1454         @result_namespace = ($1)
1455     }
1456     else {
1457         # Relative namespace
1458         @result_namespace = ($schema_class, $ns);
1459     }
1460
1461     return wantarray ? @result_namespace : join '::', @result_namespace;
1462 }
1463
1464 # Create class with applicable bases, setup monikers, etc
1465 sub _make_src_class {
1466     my ($self, $table) = @_;
1467
1468     my $schema       = $self->schema;
1469     my $schema_class = $self->schema_class;
1470
1471     my $table_moniker = $self->_table2moniker($table);
1472     my @result_namespace = ($schema_class);
1473     if ($self->use_namespaces) {
1474         my $result_namespace = $self->result_namespace || 'Result';
1475         @result_namespace = $self->_result_namespace(
1476             $schema_class,
1477             $result_namespace,
1478         );
1479     }
1480     my $table_class = join(q{::}, @result_namespace, $table_moniker);
1481
1482     if ((my $upgrading_v = $self->_upgrading_from)
1483             || $self->_rewriting) {
1484         local $self->naming->{monikers} = $upgrading_v
1485             if $upgrading_v;
1486
1487         my @result_namespace = @result_namespace;
1488         if ($self->_upgrading_from_load_classes) {
1489             @result_namespace = ($schema_class);
1490         }
1491         elsif (my $ns = $self->_downgrading_to_load_classes) {
1492             @result_namespace = $self->_result_namespace(
1493                 $schema_class,
1494                 $ns,
1495             );
1496         }
1497         elsif ($ns = $self->_rewriting_result_namespace) {
1498             @result_namespace = $self->_result_namespace(
1499                 $schema_class,
1500                 $ns,
1501             );
1502         }
1503
1504         my $old_class = join(q{::}, @result_namespace,
1505             $self->_table2moniker($table));
1506
1507         $self->_upgrading_classes->{$table_class} = $old_class
1508             unless $table_class eq $old_class;
1509     }
1510
1511 # this was a bad idea, should be ok now without it
1512 #    my $table_normalized = lc $table;
1513 #    $self->classes->{$table_normalized} = $table_class;
1514 #    $self->monikers->{$table_normalized} = $table_moniker;
1515
1516     $self->classes->{$table} = $table_class;
1517     $self->monikers->{$table} = $table_moniker;
1518
1519     $self->_use   ($table_class, @{$self->additional_classes});
1520     $self->_inject($table_class, @{$self->left_base_classes});
1521
1522     if (my @components = @{ $self->components }) {
1523         $self->_dbic_stmt($table_class, 'load_components', @components);
1524     }
1525
1526     $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1527         if @{$self->resultset_components};
1528     $self->_inject($table_class, @{$self->additional_base_classes});
1529 }
1530
1531 sub _resolve_col_accessor_collisions {
1532     my ($self, $table, $col_info) = @_;
1533
1534     my $base       = $self->result_base_class || 'DBIx::Class::Core';
1535     my @components = map "DBIx::Class::$_", @{ $self->components || [] };
1536
1537     my $table_name = ref $table ? $$table : $table;
1538
1539     my @methods;
1540
1541     for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
1542         eval "require ${class};";
1543         die $@ if $@;
1544
1545         push @methods, @{ Class::Inspector->methods($class) || [] };
1546         push @methods, @{ Class::Inspector->methods('UNIVERSAL') || [] };
1547     }
1548
1549     my %methods;
1550     @methods{@methods} = ();
1551
1552     # futureproof meta
1553     $methods{meta} = undef;
1554
1555     while (my ($col, $info) = each %$col_info) {
1556         my $accessor = $info->{accessor} || $col;
1557
1558         next if $accessor eq 'id'; # special case (very common column)
1559
1560         if (exists $methods{$accessor}) {
1561             my $mapped = 0;
1562
1563             if (my $map = $self->col_collision_map) {
1564                 for my $re (keys %$map) {
1565                     if (my @matches = $col =~ /$re/) {
1566                         $info->{accessor} = sprintf $map->{$re}, @matches;
1567                         $mapped = 1;
1568                     }
1569                 }
1570             }
1571
1572             if (not $mapped) {
1573                 warn <<"EOF";
1574 Column $col in table $table_name collides with an inherited method.
1575 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1576 EOF
1577                 $info->{accessor} = undef;
1578             }
1579         }
1580     }
1581 }
1582
1583 sub _make_column_accessor_name {
1584     my ($self, $column_name) = @_;
1585
1586     return join '_', map lc, split_name $column_name;
1587 }
1588
1589 # Set up metadata (cols, pks, etc)
1590 sub _setup_src_meta {
1591     my ($self, $table) = @_;
1592
1593     my $schema       = $self->schema;
1594     my $schema_class = $self->schema_class;
1595
1596     my $table_class = $self->classes->{$table};
1597     my $table_moniker = $self->monikers->{$table};
1598
1599     my $table_name = $table;
1600     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
1601
1602     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1603         $table_name = \ $self->_quote_table_name($table_name);
1604     }
1605
1606     my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1607
1608     # be careful to not create refs Data::Dump can "optimize"
1609     $full_table_name    = \do {"".$full_table_name} if ref $table_name;
1610
1611     $self->_dbic_stmt($table_class, 'table', $full_table_name);
1612
1613     my $cols = $self->_table_columns($table);
1614     my $col_info = $self->__columns_info_for($table);
1615
1616     while (my ($col, $info) = each %$col_info) {
1617         if ($col =~ /\W/) {
1618             ($info->{accessor} = $col) =~ s/\W+/_/g;
1619         }
1620     }
1621
1622     if ($self->preserve_case) {
1623         while (my ($col, $info) = each %$col_info) {
1624             if ($col ne lc($col)) {
1625                 if ((not exists $self->naming->{column_accessors}) || (($self->naming->{column_accessors} =~ /(\d+)/)[0] >= 7)) {
1626                     $info->{accessor} = $self->_make_column_accessor_name($info->{accessor} || $col);
1627                 }
1628                 else {
1629                     $info->{accessor} = lc($info->{accessor} || $col);
1630                 }
1631             }
1632         }
1633     }
1634     else {
1635         # XXX this needs to go away
1636         $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1637     }
1638
1639     $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
1640
1641     my $fks = $self->_table_fk_info($table);
1642
1643     foreach my $fkdef (@$fks) {
1644         for my $col (@{ $fkdef->{local_columns} }) {
1645             $col_info->{$col}{is_foreign_key} = 1;
1646         }
1647     }
1648
1649     my $pks = $self->_table_pk_info($table) || [];
1650
1651     foreach my $pkcol (@$pks) {
1652         $col_info->{$pkcol}{is_nullable} = 0;
1653     }
1654
1655     $self->_dbic_stmt(
1656         $table_class,
1657         'add_columns',
1658         map { $_, ($col_info->{$_}||{}) } @$cols
1659     );
1660
1661     my %uniq_tag; # used to eliminate duplicate uniqs
1662
1663     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1664           : carp("$table has no primary key");
1665     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1666
1667     my $uniqs = $self->_table_uniq_info($table) || [];
1668     for (@$uniqs) {
1669         my ($name, $cols) = @$_;
1670         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1671         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1672     }
1673
1674 }
1675
1676 sub __columns_info_for {
1677     my ($self, $table) = @_;
1678
1679     my $result = $self->_columns_info_for($table);
1680
1681     while (my ($col, $info) = each %$result) {
1682         $info = { %$info, %{ $self->_custom_column_info  ($table, $col, $info) } };
1683         $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1684
1685         $result->{$col} = $info;
1686     }
1687
1688     return $result;
1689 }
1690
1691 =head2 tables
1692
1693 Returns a sorted list of loaded tables, using the original database table
1694 names.
1695
1696 =cut
1697
1698 sub tables {
1699     my $self = shift;
1700
1701     return keys %{$self->_tables};
1702 }
1703
1704 # Make a moniker from a table
1705 sub _default_table2moniker {
1706     no warnings 'uninitialized';
1707     my ($self, $table) = @_;
1708
1709     if ($self->naming->{monikers} eq 'v4') {
1710         return join '', map ucfirst, split /[\W_]+/, lc $table;
1711     }
1712     elsif ($self->naming->{monikers} eq 'v5') {
1713         return join '', map ucfirst, split /[\W_]+/,
1714             Lingua::EN::Inflect::Number::to_S(lc $table);
1715     }
1716     elsif ($self->naming->{monikers} eq 'v6') {
1717         (my $as_phrase = lc $table) =~ s/_+/ /g;
1718         my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1719
1720         return join '', map ucfirst, split /\W+/, $inflected;
1721     }
1722
1723     my @words = map lc, split_name $table;
1724     my $as_phrase = join ' ', @words;
1725
1726     my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1727
1728     return join '', map ucfirst, split /\W+/, $inflected;
1729 }
1730
1731 sub _table2moniker {
1732     my ( $self, $table ) = @_;
1733
1734     my $moniker;
1735
1736     if( ref $self->moniker_map eq 'HASH' ) {
1737         $moniker = $self->moniker_map->{$table};
1738     }
1739     elsif( ref $self->moniker_map eq 'CODE' ) {
1740         $moniker = $self->moniker_map->($table);
1741     }
1742
1743     $moniker ||= $self->_default_table2moniker($table);
1744
1745     return $moniker;
1746 }
1747
1748 sub _load_relationships {
1749     my ($self, $table) = @_;
1750
1751     my $tbl_fk_info = $self->_table_fk_info($table);
1752     foreach my $fkdef (@$tbl_fk_info) {
1753         $fkdef->{remote_source} =
1754             $self->monikers->{delete $fkdef->{remote_table}};
1755     }
1756     my $tbl_uniq_info = $self->_table_uniq_info($table);
1757
1758     my $local_moniker = $self->monikers->{$table};
1759     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1760
1761     foreach my $src_class (sort keys %$rel_stmts) {
1762         my $src_stmts = $rel_stmts->{$src_class};
1763         foreach my $stmt (@$src_stmts) {
1764             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1765         }
1766     }
1767 }
1768
1769 # Overload these in driver class:
1770
1771 # Returns an arrayref of column names
1772 sub _table_columns { croak "ABSTRACT METHOD" }
1773
1774 # Returns arrayref of pk col names
1775 sub _table_pk_info { croak "ABSTRACT METHOD" }
1776
1777 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1778 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1779
1780 # Returns an arrayref of foreign key constraints, each
1781 #   being a hashref with 3 keys:
1782 #   local_columns (arrayref), remote_columns (arrayref), remote_table
1783 sub _table_fk_info { croak "ABSTRACT METHOD" }
1784
1785 # Returns an array of lower case table names
1786 sub _tables_list { croak "ABSTRACT METHOD" }
1787
1788 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1789 sub _dbic_stmt {
1790     my $self   = shift;
1791     my $class  = shift;
1792     my $method = shift;
1793
1794     # generate the pod for this statement, storing it with $self->_pod
1795     $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
1796
1797     my $args = dump(@_);
1798     $args = '(' . $args . ')' if @_ < 2;
1799     my $stmt = $method . $args . q{;};
1800
1801     warn qq|$class\->$stmt\n| if $self->debug;
1802     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1803     return;
1804 }
1805
1806 # generates the accompanying pod for a DBIC class method statement,
1807 # storing it with $self->_pod
1808 sub _make_pod {
1809     my $self   = shift;
1810     my $class  = shift;
1811     my $method = shift;
1812
1813     if ( $method eq 'table' ) {
1814         my ($table) = @_;
1815         my $pcm = $self->pod_comment_mode;
1816         my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
1817         $comment = $self->__table_comment($table);
1818         $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1819         $comment_in_name   = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1820         $comment_in_desc   = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
1821         $self->_pod( $class, "=head1 NAME" );
1822         my $table_descr = $class;
1823         $table_descr .= " - " . $comment if $comment and $comment_in_name;
1824         $self->{_class2table}{ $class } = $table;
1825         $self->_pod( $class, $table_descr );
1826         if ($comment and $comment_in_desc) {
1827             $self->_pod( $class, "=head1 DESCRIPTION" );
1828             $self->_pod( $class, $comment );
1829         }
1830         $self->_pod_cut( $class );
1831     } elsif ( $method eq 'add_columns' ) {
1832         $self->_pod( $class, "=head1 ACCESSORS" );
1833         my $col_counter = 0;
1834         my @cols = @_;
1835         while( my ($name,$attrs) = splice @cols,0,2 ) {
1836             $col_counter++;
1837             $self->_pod( $class, '=head2 ' . $name  );
1838             $self->_pod( $class,
1839                 join "\n", map {
1840                     my $s = $attrs->{$_};
1841                     $s = !defined $s          ? 'undef'             :
1842                         length($s) == 0       ? '(empty string)'    :
1843                         ref($s) eq 'SCALAR'   ? $$s                 :
1844                         ref($s)               ? dumper_squashed $s  :
1845                         looks_like_number($s) ? $s                  : qq{'$s'};
1846
1847                     "  $_: $s"
1848                  } sort keys %$attrs,
1849             );
1850             if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
1851                 $self->_pod( $class, $comment );
1852             }
1853         }
1854         $self->_pod_cut( $class );
1855     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1856         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1857         my ( $accessor, $rel_class ) = @_;
1858         $self->_pod( $class, "=head2 $accessor" );
1859         $self->_pod( $class, 'Type: ' . $method );
1860         $self->_pod( $class, "Related object: L<$rel_class>" );
1861         $self->_pod_cut( $class );
1862         $self->{_relations_started} { $class } = 1;
1863     }
1864 }
1865
1866 sub _filter_comment {
1867     my ($self, $txt) = @_;
1868
1869     $txt = '' if not defined $txt;
1870
1871     $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
1872
1873     return $txt;
1874 }
1875
1876 sub __table_comment {
1877     my $self = shift;
1878
1879     if (my $code = $self->can('_table_comment')) {
1880         return $self->_filter_comment($self->$code(@_));
1881     }
1882     
1883     return '';
1884 }
1885
1886 sub __column_comment {
1887     my $self = shift;
1888
1889     if (my $code = $self->can('_column_comment')) {
1890         return $self->_filter_comment($self->$code(@_));
1891     }
1892
1893     return '';
1894 }
1895
1896 # Stores a POD documentation
1897 sub _pod {
1898     my ($self, $class, $stmt) = @_;
1899     $self->_raw_stmt( $class, "\n" . $stmt  );
1900 }
1901
1902 sub _pod_cut {
1903     my ($self, $class ) = @_;
1904     $self->_raw_stmt( $class, "\n=cut\n" );
1905 }
1906
1907 # Store a raw source line for a class (for dumping purposes)
1908 sub _raw_stmt {
1909     my ($self, $class, $stmt) = @_;
1910     push(@{$self->{_dump_storage}->{$class}}, $stmt);
1911 }
1912
1913 # Like above, but separately for the externally loaded stuff
1914 sub _ext_stmt {
1915     my ($self, $class, $stmt) = @_;
1916     push(@{$self->{_ext_storage}->{$class}}, $stmt);
1917 }
1918
1919 sub _quote_table_name {
1920     my ($self, $table) = @_;
1921
1922     my $qt = $self->schema->storage->sql_maker->quote_char;
1923
1924     return $table unless $qt;
1925
1926     if (ref $qt) {
1927         return $qt->[0] . $table . $qt->[1];
1928     }
1929
1930     return $qt . $table . $qt;
1931 }
1932
1933 sub _custom_column_info {
1934     my ( $self, $table_name, $column_name, $column_info ) = @_;
1935
1936     if (my $code = $self->custom_column_info) {
1937         return $code->($table_name, $column_name, $column_info) || {};
1938     }
1939     return {};
1940 }
1941
1942 sub _datetime_column_info {
1943     my ( $self, $table_name, $column_name, $column_info ) = @_;
1944     my $result = {};
1945     my $type = $column_info->{data_type} || '';
1946     if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
1947             or ($type =~ /date|timestamp/i)) {
1948         $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
1949         $result->{locale}   = $self->datetime_locale   if $self->datetime_locale;
1950     }
1951     return $result;
1952 }
1953
1954 sub _lc {
1955     my ($self, $name) = @_;
1956
1957     return $self->preserve_case ? $name : lc($name);
1958 }
1959
1960 sub _uc {
1961     my ($self, $name) = @_;
1962
1963     return $self->preserve_case ? $name : uc($name);
1964 }
1965
1966 sub _unregister_source_for_table {
1967     my ($self, $table) = @_;
1968
1969     eval {
1970         local $@;
1971         my $schema = $self->schema;
1972         # in older DBIC it's a private method
1973         my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
1974         $schema->$unregister($self->_table2moniker($table));
1975         delete $self->monikers->{$table};
1976         delete $self->classes->{$table};
1977         delete $self->_upgrading_classes->{$table};
1978         delete $self->{_tables}{$table};
1979     };
1980 }
1981
1982 # remove the dump dir from @INC on destruction
1983 sub DESTROY {
1984     my $self = shift;
1985
1986     @INC = grep $_ ne $self->dump_directory, @INC;
1987 }
1988
1989 =head2 monikers
1990
1991 Returns a hashref of loaded table to moniker mappings.  There will
1992 be two entries for each table, the original name and the "normalized"
1993 name, in the case that the two are different (such as databases
1994 that like uppercase table names, or preserve your original mixed-case
1995 definitions, or what-have-you).
1996
1997 =head2 classes
1998
1999 Returns a hashref of table to class mappings.  In some cases it will
2000 contain multiple entries per table for the original and normalized table
2001 names, as above in L</monikers>.
2002
2003 =head1 COLUMN ACCESSOR COLLISIONS
2004
2005 Occasionally you may have a column name that collides with a perl method, such
2006 as C<can>. In such cases, the default action is to set the C<accessor> of the
2007 column spec to C<undef>.
2008
2009 You can then name the accessor yourself by placing code such as the following
2010 below the md5:
2011
2012     __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2013
2014 Another option is to use the L</col_collision_map> option.
2015
2016 =head1 SEE ALSO
2017
2018 L<DBIx::Class::Schema::Loader>
2019
2020 =head1 AUTHOR
2021
2022 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2023
2024 =head1 LICENSE
2025
2026 This library is free software; you can redistribute it and/or modify it under
2027 the same terms as Perl itself.
2028
2029 =cut
2030
2031 1;
2032 # vim:et sts=4 sw=4 tw=0: