62391c44929f84133b6624de7c4613373c7c00b6
[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::Phrase/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::Phrase/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 THE FIRST PART OF THIS FILE>
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<sprintf|perlfunc/sprintf> format or a hashref of
492 strings which are compiled to regular expressions that map to
493 L<sprintf|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         my $code = $self->_rewrite_old_classnames(scalar slurp $real_inc_path);
869
870         if ($self->dynamic) { # load the class too
871             eval_without_redefine_warnings($code);
872         }
873
874         $self->_ext_stmt($class,
875           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
876          .qq|# They are now part of the custom portion of this file\n|
877          .qq|# for you to hand-edit.  If you do not either delete\n|
878          .qq|# this section or remove that file from \@INC, this section\n|
879          .qq|# will be repeated redundantly when you re-create this\n|
880          .qq|# file again via Loader!  See skip_load_external to disable\n|
881          .qq|# this feature.\n|
882         );
883         chomp $code;
884         $self->_ext_stmt($class, $code);
885         $self->_ext_stmt($class,
886             qq|# End of lines loaded from '$real_inc_path' |
887         );
888     }
889
890     if ($old_real_inc_path) {
891         my $code = slurp $old_real_inc_path;
892
893         $self->_ext_stmt($class, <<"EOF");
894
895 # These lines were loaded from '$old_real_inc_path',
896 # based on the Result class name that would have been created by an older
897 # version of the Loader. For a static schema, this happens only once during
898 # upgrade. See skip_load_external to disable this feature.
899 EOF
900
901         $code = $self->_rewrite_old_classnames($code);
902
903         if ($self->dynamic) {
904             warn <<"EOF";
905
906 Detected external content in '$old_real_inc_path', a class name that would have
907 been used by an older version of the Loader.
908
909 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
910 new name of the Result.
911 EOF
912             eval_without_redefine_warnings($code);
913         }
914
915         chomp $code;
916         $self->_ext_stmt($class, $code);
917         $self->_ext_stmt($class,
918             qq|# End of lines loaded from '$old_real_inc_path' |
919         );
920     }
921 }
922
923 =head2 load
924
925 Does the actual schema-construction work.
926
927 =cut
928
929 sub load {
930     my $self = shift;
931
932     $self->_load_tables(
933         $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
934     );
935 }
936
937 =head2 rescan
938
939 Arguments: schema
940
941 Rescan the database for changes. Returns a list of the newly added table
942 monikers.
943
944 The schema argument should be the schema class or object to be affected.  It
945 should probably be derived from the original schema_class used during L</load>.
946
947 =cut
948
949 sub rescan {
950     my ($self, $schema) = @_;
951
952     $self->{schema} = $schema;
953     $self->_relbuilder->{schema} = $schema;
954
955     my @created;
956     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
957
958     foreach my $table (@current) {
959         if(!exists $self->{_tables}->{$table}) {
960             push(@created, $table);
961         }
962     }
963
964     my %current;
965     @current{@current} = ();
966     foreach my $table (keys %{ $self->{_tables} }) {
967         if (not exists $current{$table}) {
968             $self->_unregister_source_for_table($table);
969         }
970     }
971
972     delete $self->{_dump_storage};
973     delete $self->{_relations_started};
974
975     my $loaded = $self->_load_tables(@current);
976
977     return map { $self->monikers->{$_} } @created;
978 }
979
980 sub _relbuilder {
981     my ($self) = @_;
982
983     return if $self->{skip_relationships};
984
985     return $self->{relbuilder} ||= do {
986
987         no warnings 'uninitialized';
988         my $relbuilder_suff =
989             {qw{
990                 v4  ::Compat::v0_040
991                 v5  ::Compat::v0_05
992                 v6  ::Compat::v0_06
993             }}
994             ->{ $self->naming->{relationships}};
995
996         my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
997         eval "require $relbuilder_class"; die $@ if $@;
998         $relbuilder_class->new( $self );
999
1000     };
1001 }
1002
1003 sub _load_tables {
1004     my ($self, @tables) = @_;
1005
1006     # Save the new tables to the tables list
1007     foreach (@tables) {
1008         $self->{_tables}->{$_} = 1;
1009     }
1010
1011     $self->_make_src_class($_) for @tables;
1012
1013     # sanity-check for moniker clashes
1014     my $inverse_moniker_idx;
1015     for (keys %{$self->monikers}) {
1016       push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1017     }
1018
1019     my @clashes;
1020     for (keys %$inverse_moniker_idx) {
1021       my $tables = $inverse_moniker_idx->{$_};
1022       if (@$tables > 1) {
1023         push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1024           join (', ', map { "'$_'" } @$tables),
1025           $_,
1026         );
1027       }
1028     }
1029
1030     if (@clashes) {
1031       die   'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1032           . 'Either change the naming style, or supply an explicit moniker_map: '
1033           . join ('; ', @clashes)
1034           . "\n"
1035       ;
1036     }
1037
1038
1039     $self->_setup_src_meta($_) for @tables;
1040
1041     if(!$self->skip_relationships) {
1042         # The relationship loader needs a working schema
1043         $self->{quiet} = 1;
1044         local $self->{dump_directory} = $self->{temp_directory};
1045         $self->_reload_classes(\@tables);
1046         $self->_load_relationships($_) for @tables;
1047         $self->{quiet} = 0;
1048
1049         # Remove that temp dir from INC so it doesn't get reloaded
1050         @INC = grep $_ ne $self->dump_directory, @INC;
1051     }
1052
1053     $self->_load_external($_)
1054         for map { $self->classes->{$_} } @tables;
1055
1056     # Reload without unloading first to preserve any symbols from external
1057     # packages.
1058     $self->_reload_classes(\@tables, 0);
1059
1060     # Drop temporary cache
1061     delete $self->{_cache};
1062
1063     return \@tables;
1064 }
1065
1066 sub _reload_classes {
1067     my ($self, $tables, $unload) = @_;
1068
1069     my @tables = @$tables;
1070     $unload = 1 unless defined $unload;
1071
1072     # so that we don't repeat custom sections
1073     @INC = grep $_ ne $self->dump_directory, @INC;
1074
1075     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1076
1077     unshift @INC, $self->dump_directory;
1078     
1079     my @to_register;
1080     my %have_source = map { $_ => $self->schema->source($_) }
1081         $self->schema->sources;
1082
1083     for my $table (@tables) {
1084         my $moniker = $self->monikers->{$table};
1085         my $class = $self->classes->{$table};
1086         
1087         {
1088             no warnings 'redefine';
1089             local *Class::C3::reinitialize = sub {};  # to speed things up, reinitialized below
1090             use warnings;
1091
1092             if (my $mc = $self->_moose_metaclass($class)) {
1093                 $mc->make_mutable;
1094             }
1095             Class::Unload->unload($class) if $unload;
1096             my ($source, $resultset_class);
1097             if (
1098                 ($source = $have_source{$moniker})
1099                 && ($resultset_class = $source->resultset_class)
1100                 && ($resultset_class ne 'DBIx::Class::ResultSet')
1101             ) {
1102                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1103                 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1104                     $mc->make_mutable;
1105                 }
1106                 Class::Unload->unload($resultset_class) if $unload;
1107                 $self->_reload_class($resultset_class) if $has_file;
1108             }
1109             $self->_reload_class($class);
1110         }
1111         push @to_register, [$moniker, $class];
1112     }
1113
1114     Class::C3->reinitialize;
1115     for (@to_register) {
1116         $self->schema->register_class(@$_);
1117     }
1118 }
1119
1120 sub _moose_metaclass {
1121   return undef unless $INC{'Class/MOP.pm'};   # if CMOP is not loaded the class could not have loaded in the 1st place
1122
1123   my $class = $_[1];
1124
1125   my $mc = try { Class::MOP::class_of($class) }
1126     or return undef;
1127
1128   return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1129 }
1130
1131 # We use this instead of ensure_class_loaded when there are package symbols we
1132 # want to preserve.
1133 sub _reload_class {
1134     my ($self, $class) = @_;
1135
1136     my $class_path = $self->_class_path($class);
1137     delete $INC{ $class_path };
1138
1139 # kill redefined warnings
1140     eval {
1141         eval_without_redefine_warnings ("require $class");
1142     };
1143     die "Failed to reload class $class: $@" if $@;
1144 }
1145
1146 sub _get_dump_filename {
1147     my ($self, $class) = (@_);
1148
1149     $class =~ s{::}{/}g;
1150     return $self->dump_directory . q{/} . $class . q{.pm};
1151 }
1152
1153 sub _ensure_dump_subdirs {
1154     my ($self, $class) = (@_);
1155
1156     my @name_parts = split(/::/, $class);
1157     pop @name_parts; # we don't care about the very last element,
1158                      # which is a filename
1159
1160     my $dir = $self->dump_directory;
1161     while (1) {
1162         if(!-d $dir) {
1163             mkdir($dir) or croak "mkdir('$dir') failed: $!";
1164         }
1165         last if !@name_parts;
1166         $dir = File::Spec->catdir($dir, shift @name_parts);
1167     }
1168 }
1169
1170 sub _dump_to_dir {
1171     my ($self, @classes) = @_;
1172
1173     my $schema_class = $self->schema_class;
1174     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1175
1176     my $target_dir = $self->dump_directory;
1177     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1178         unless $self->{dynamic} or $self->{quiet};
1179
1180     my $schema_text =
1181           qq|package $schema_class;\n\n|
1182         . qq|# Created by DBIx::Class::Schema::Loader\n|
1183         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1184         . qq|use strict;\nuse warnings;\n\n|;
1185     if ($self->use_moose) {
1186         $schema_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1187     }
1188     else {
1189         $schema_text .= qq|use base '$schema_base_class';\n\n|;
1190     }
1191
1192     if ($self->use_namespaces) {
1193         $schema_text .= qq|__PACKAGE__->load_namespaces|;
1194         my $namespace_options;
1195
1196         my @attr = qw/resultset_namespace default_resultset_class/;
1197
1198         unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1199
1200         for my $attr (@attr) {
1201             if ($self->$attr) {
1202                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
1203             }
1204         }
1205         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1206         $schema_text .= qq|;\n|;
1207     }
1208     else {
1209         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1210     }
1211
1212     {
1213         local $self->{version_to_dump} = $self->schema_version_to_dump;
1214         $self->_write_classfile($schema_class, $schema_text, 1);
1215     }
1216
1217     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1218
1219     foreach my $src_class (@classes) {
1220         my $src_text = 
1221               qq|package $src_class;\n\n|
1222             . qq|# Created by DBIx::Class::Schema::Loader\n|
1223             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1224             . qq|use strict;\nuse warnings;\n\n|;
1225         if ($self->use_moose) {
1226             $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1227
1228             # these options 'use base' which is compile time
1229             if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1230                 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1231             }
1232             else {
1233                 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1234             }
1235         }
1236         else {
1237              $src_text .= qq|use base '$result_base_class';\n\n|;
1238         }
1239         $self->_write_classfile($src_class, $src_text);
1240     }
1241
1242     # remove Result dir if downgrading from use_namespaces, and there are no
1243     # files left.
1244     if (my $result_ns = $self->_downgrading_to_load_classes
1245                         || $self->_rewriting_result_namespace) {
1246         my $result_namespace = $self->_result_namespace(
1247             $schema_class,
1248             $result_ns,
1249         );
1250
1251         (my $result_dir = $result_namespace) =~ s{::}{/}g;
1252         $result_dir = $self->dump_directory . '/' . $result_dir;
1253
1254         unless (my @files = glob "$result_dir/*") {
1255             rmdir $result_dir;
1256         }
1257     }
1258
1259     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1260
1261 }
1262
1263 sub _sig_comment {
1264     my ($self, $version, $ts) = @_;
1265     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1266          . qq| v| . $version
1267          . q| @ | . $ts 
1268          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1269 }
1270
1271 sub _write_classfile {
1272     my ($self, $class, $text, $is_schema) = @_;
1273
1274     my $filename = $self->_get_dump_filename($class);
1275     $self->_ensure_dump_subdirs($class);
1276
1277     if (-f $filename && $self->really_erase_my_files) {
1278         warn "Deleting existing file '$filename' due to "
1279             . "'really_erase_my_files' setting\n" unless $self->{quiet};
1280         unlink($filename);
1281     }
1282
1283     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1284         = $self->_parse_generated_file($filename);
1285
1286     if (! $old_gen && -f $filename) {
1287         croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1288             . " it does not appear to have been generated by Loader"
1289     }
1290
1291     my $custom_content = $old_custom || '';
1292
1293     # prepend extra custom content from a *renamed* class (singularization effect)
1294     if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1295         my $old_filename = $self->_get_dump_filename($renamed_class);
1296
1297         if (-f $old_filename) {
1298             my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1299
1300             $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1301
1302             $custom_content = join ("\n", '', $extra_custom, $custom_content)
1303                 if $extra_custom;
1304
1305             unlink $old_filename;
1306         }
1307     }
1308
1309     $custom_content ||= $self->_default_custom_content;
1310
1311     # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1312     # If there is already custom content, which does not have the Moose content, add it.
1313     if ($self->use_moose) {
1314
1315         my $non_moose_custom_content = do {
1316             local $self->{use_moose} = 0;
1317             $self->_default_custom_content;
1318         };
1319
1320         if ($custom_content eq $non_moose_custom_content) {
1321             $custom_content = $self->_default_custom_content;
1322         }
1323         elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content]}\E/) {
1324             $custom_content .= $self->_default_custom_content;
1325         }
1326     }
1327     elsif (defined $self->use_moose && $old_gen) {
1328         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'
1329             if $old_gen =~ /use \s+ MooseX?\b/x;
1330     }
1331
1332     $custom_content = $self->_rewrite_old_classnames($custom_content);
1333
1334     $text .= qq|$_\n|
1335         for @{$self->{_dump_storage}->{$class} || []};
1336
1337     # Check and see if the dump is infact differnt
1338
1339     my $compare_to;
1340     if ($old_md5) {
1341       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1342       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
1343         return unless $self->_upgrading_from && $is_schema;
1344       }
1345     }
1346
1347     $text .= $self->_sig_comment(
1348       $self->version_to_dump,
1349       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1350     );
1351
1352     open(my $fh, '>', $filename)
1353         or croak "Cannot open '$filename' for writing: $!";
1354
1355     # Write the top half and its MD5 sum
1356     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1357
1358     # Write out anything loaded via external partial class file in @INC
1359     print $fh qq|$_\n|
1360         for @{$self->{_ext_storage}->{$class} || []};
1361
1362     # Write out any custom content the user has added
1363     print $fh $custom_content;
1364
1365     close($fh)
1366         or croak "Error closing '$filename': $!";
1367 }
1368
1369 sub _default_moose_custom_content {
1370     return qq|\n__PACKAGE__->meta->make_immutable;|;
1371 }
1372
1373 sub _default_custom_content {
1374     my $self = shift;
1375     my $default = qq|\n\n# You can replace this text with custom|
1376          . qq| code or comments, and it will be preserved on regeneration|;
1377     if ($self->use_moose) {
1378         $default .= $self->_default_moose_custom_content;
1379     }
1380     $default .= qq|\n1;\n|;
1381     return $default;
1382 }
1383
1384 sub _parse_generated_file {
1385     my ($self, $fn) = @_;
1386
1387     return unless -f $fn;
1388
1389     open(my $fh, '<', $fn)
1390         or croak "Cannot open '$fn' for reading: $!";
1391
1392     my $mark_re =
1393         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1394
1395     my ($md5, $ts, $ver, $gen);
1396     while(<$fh>) {
1397         if(/$mark_re/) {
1398             my $pre_md5 = $1;
1399             $md5 = $2;
1400
1401             # Pull out the version and timestamp from the line above
1402             ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
1403
1404             $gen .= $pre_md5;
1405             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"
1406                 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
1407
1408             last;
1409         }
1410         else {
1411             $gen .= $_;
1412         }
1413     }
1414
1415     my $custom = do { local $/; <$fh> }
1416         if $md5;
1417
1418     close ($fh);
1419
1420     return ($gen, $md5, $ver, $ts, $custom);
1421 }
1422
1423 sub _use {
1424     my $self = shift;
1425     my $target = shift;
1426
1427     foreach (@_) {
1428         warn "$target: use $_;" if $self->debug;
1429         $self->_raw_stmt($target, "use $_;");
1430     }
1431 }
1432
1433 sub _inject {
1434     my $self = shift;
1435     my $target = shift;
1436
1437     my $blist = join(q{ }, @_);
1438
1439     return unless $blist;
1440
1441     warn "$target: use base qw/$blist/;" if $self->debug;
1442     $self->_raw_stmt($target, "use base qw/$blist/;");
1443 }
1444
1445 sub _result_namespace {
1446     my ($self, $schema_class, $ns) = @_;
1447     my @result_namespace;
1448
1449     if ($ns =~ /^\+(.*)/) {
1450         # Fully qualified namespace
1451         @result_namespace = ($1)
1452     }
1453     else {
1454         # Relative namespace
1455         @result_namespace = ($schema_class, $ns);
1456     }
1457
1458     return wantarray ? @result_namespace : join '::', @result_namespace;
1459 }
1460
1461 # Create class with applicable bases, setup monikers, etc
1462 sub _make_src_class {
1463     my ($self, $table) = @_;
1464
1465     my $schema       = $self->schema;
1466     my $schema_class = $self->schema_class;
1467
1468     my $table_moniker = $self->_table2moniker($table);
1469     my @result_namespace = ($schema_class);
1470     if ($self->use_namespaces) {
1471         my $result_namespace = $self->result_namespace || 'Result';
1472         @result_namespace = $self->_result_namespace(
1473             $schema_class,
1474             $result_namespace,
1475         );
1476     }
1477     my $table_class = join(q{::}, @result_namespace, $table_moniker);
1478
1479     if ((my $upgrading_v = $self->_upgrading_from)
1480             || $self->_rewriting) {
1481         local $self->naming->{monikers} = $upgrading_v
1482             if $upgrading_v;
1483
1484         my @result_namespace = @result_namespace;
1485         if ($self->_upgrading_from_load_classes) {
1486             @result_namespace = ($schema_class);
1487         }
1488         elsif (my $ns = $self->_downgrading_to_load_classes) {
1489             @result_namespace = $self->_result_namespace(
1490                 $schema_class,
1491                 $ns,
1492             );
1493         }
1494         elsif ($ns = $self->_rewriting_result_namespace) {
1495             @result_namespace = $self->_result_namespace(
1496                 $schema_class,
1497                 $ns,
1498             );
1499         }
1500
1501         my $old_class = join(q{::}, @result_namespace,
1502             $self->_table2moniker($table));
1503
1504         $self->_upgrading_classes->{$table_class} = $old_class
1505             unless $table_class eq $old_class;
1506     }
1507
1508 # this was a bad idea, should be ok now without it
1509 #    my $table_normalized = lc $table;
1510 #    $self->classes->{$table_normalized} = $table_class;
1511 #    $self->monikers->{$table_normalized} = $table_moniker;
1512
1513     $self->classes->{$table} = $table_class;
1514     $self->monikers->{$table} = $table_moniker;
1515
1516     $self->_use   ($table_class, @{$self->additional_classes});
1517     $self->_inject($table_class, @{$self->left_base_classes});
1518
1519     if (my @components = @{ $self->components }) {
1520         $self->_dbic_stmt($table_class, 'load_components', @components);
1521     }
1522
1523     $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1524         if @{$self->resultset_components};
1525     $self->_inject($table_class, @{$self->additional_base_classes});
1526 }
1527
1528 sub _resolve_col_accessor_collisions {
1529     my ($self, $table, $col_info) = @_;
1530
1531     my $base       = $self->result_base_class || 'DBIx::Class::Core';
1532     my @components = map "DBIx::Class::$_", @{ $self->components || [] };
1533
1534     my $table_name = ref $table ? $$table : $table;
1535
1536     my @methods;
1537
1538     for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
1539         eval "require ${class};";
1540         die $@ if $@;
1541
1542         push @methods, @{ Class::Inspector->methods($class) || [] };
1543         push @methods, @{ Class::Inspector->methods('UNIVERSAL') || [] };
1544     }
1545
1546     my %methods;
1547     @methods{@methods} = ();
1548
1549     # futureproof meta
1550     $methods{meta} = undef;
1551
1552     while (my ($col, $info) = each %$col_info) {
1553         my $accessor = $info->{accessor} || $col;
1554
1555         next if $accessor eq 'id'; # special case (very common column)
1556
1557         if (exists $methods{$accessor}) {
1558             my $mapped = 0;
1559
1560             if (my $map = $self->col_collision_map) {
1561                 for my $re (keys %$map) {
1562                     if (my @matches = $col =~ /$re/) {
1563                         $info->{accessor} = sprintf $map->{$re}, @matches;
1564                         $mapped = 1;
1565                     }
1566                 }
1567             }
1568
1569             if (not $mapped) {
1570                 warn <<"EOF";
1571 Column $col in table $table_name collides with an inherited method.
1572 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1573 EOF
1574                 $info->{accessor} = undef;
1575             }
1576         }
1577     }
1578 }
1579
1580 sub _make_column_accessor_name {
1581     my ($self, $column_name) = @_;
1582
1583     return join '_', map lc, split_name $column_name;
1584 }
1585
1586 # Set up metadata (cols, pks, etc)
1587 sub _setup_src_meta {
1588     my ($self, $table) = @_;
1589
1590     my $schema       = $self->schema;
1591     my $schema_class = $self->schema_class;
1592
1593     my $table_class = $self->classes->{$table};
1594     my $table_moniker = $self->monikers->{$table};
1595
1596     my $table_name = $table;
1597     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
1598
1599     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1600         $table_name = \ $self->_quote_table_name($table_name);
1601     }
1602
1603     my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1604
1605     # be careful to not create refs Data::Dump can "optimize"
1606     $full_table_name    = \do {"".$full_table_name} if ref $table_name;
1607
1608     $self->_dbic_stmt($table_class, 'table', $full_table_name);
1609
1610     my $cols = $self->_table_columns($table);
1611     my $col_info = $self->__columns_info_for($table);
1612
1613     while (my ($col, $info) = each %$col_info) {
1614         if ($col =~ /\W/) {
1615             ($info->{accessor} = $col) =~ s/\W+/_/g;
1616         }
1617     }
1618
1619     if ($self->preserve_case) {
1620         while (my ($col, $info) = each %$col_info) {
1621             if ($col ne lc($col)) {
1622                 if ((not exists $self->naming->{column_accessors}) || (($self->naming->{column_accessors} =~ /(\d+)/)[0] >= 7)) {
1623                     $info->{accessor} = $self->_make_column_accessor_name($info->{accessor} || $col);
1624                 }
1625                 else {
1626                     $info->{accessor} = lc($info->{accessor} || $col);
1627                 }
1628             }
1629         }
1630     }
1631     else {
1632         # XXX this needs to go away
1633         $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1634     }
1635
1636     $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
1637
1638     my $fks = $self->_table_fk_info($table);
1639
1640     foreach my $fkdef (@$fks) {
1641         for my $col (@{ $fkdef->{local_columns} }) {
1642             $col_info->{$col}{is_foreign_key} = 1;
1643         }
1644     }
1645
1646     my $pks = $self->_table_pk_info($table) || [];
1647
1648     foreach my $pkcol (@$pks) {
1649         $col_info->{$pkcol}{is_nullable} = 0;
1650     }
1651
1652     $self->_dbic_stmt(
1653         $table_class,
1654         'add_columns',
1655         map { $_, ($col_info->{$_}||{}) } @$cols
1656     );
1657
1658     my %uniq_tag; # used to eliminate duplicate uniqs
1659
1660     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1661           : carp("$table has no primary key");
1662     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1663
1664     my $uniqs = $self->_table_uniq_info($table) || [];
1665     for (@$uniqs) {
1666         my ($name, $cols) = @$_;
1667         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1668         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1669     }
1670
1671 }
1672
1673 sub __columns_info_for {
1674     my ($self, $table) = @_;
1675
1676     my $result = $self->_columns_info_for($table);
1677
1678     while (my ($col, $info) = each %$result) {
1679         $info = { %$info, %{ $self->_custom_column_info  ($table, $col, $info) } };
1680         $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1681
1682         $result->{$col} = $info;
1683     }
1684
1685     return $result;
1686 }
1687
1688 =head2 tables
1689
1690 Returns a sorted list of loaded tables, using the original database table
1691 names.
1692
1693 =cut
1694
1695 sub tables {
1696     my $self = shift;
1697
1698     return keys %{$self->_tables};
1699 }
1700
1701 # Make a moniker from a table
1702 sub _default_table2moniker {
1703     no warnings 'uninitialized';
1704     my ($self, $table) = @_;
1705
1706     if ($self->naming->{monikers} eq 'v4') {
1707         return join '', map ucfirst, split /[\W_]+/, lc $table;
1708     }
1709     elsif ($self->naming->{monikers} eq 'v5') {
1710         return join '', map ucfirst, split /[\W_]+/,
1711             Lingua::EN::Inflect::Number::to_S(lc $table);
1712     }
1713     elsif ($self->naming->{monikers} eq 'v6') {
1714         (my $as_phrase = lc $table) =~ s/_+/ /g;
1715         my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1716
1717         return join '', map ucfirst, split /\W+/, $inflected;
1718     }
1719
1720     my @words = map lc, split_name $table;
1721     my $as_phrase = join ' ', @words;
1722
1723     my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1724
1725     return join '', map ucfirst, split /\W+/, $inflected;
1726 }
1727
1728 sub _table2moniker {
1729     my ( $self, $table ) = @_;
1730
1731     my $moniker;
1732
1733     if( ref $self->moniker_map eq 'HASH' ) {
1734         $moniker = $self->moniker_map->{$table};
1735     }
1736     elsif( ref $self->moniker_map eq 'CODE' ) {
1737         $moniker = $self->moniker_map->($table);
1738     }
1739
1740     $moniker ||= $self->_default_table2moniker($table);
1741
1742     return $moniker;
1743 }
1744
1745 sub _load_relationships {
1746     my ($self, $table) = @_;
1747
1748     my $tbl_fk_info = $self->_table_fk_info($table);
1749     foreach my $fkdef (@$tbl_fk_info) {
1750         $fkdef->{remote_source} =
1751             $self->monikers->{delete $fkdef->{remote_table}};
1752     }
1753     my $tbl_uniq_info = $self->_table_uniq_info($table);
1754
1755     my $local_moniker = $self->monikers->{$table};
1756     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1757
1758     foreach my $src_class (sort keys %$rel_stmts) {
1759         my $src_stmts = $rel_stmts->{$src_class};
1760         foreach my $stmt (@$src_stmts) {
1761             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1762         }
1763     }
1764 }
1765
1766 # Overload these in driver class:
1767
1768 # Returns an arrayref of column names
1769 sub _table_columns { croak "ABSTRACT METHOD" }
1770
1771 # Returns arrayref of pk col names
1772 sub _table_pk_info { croak "ABSTRACT METHOD" }
1773
1774 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1775 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1776
1777 # Returns an arrayref of foreign key constraints, each
1778 #   being a hashref with 3 keys:
1779 #   local_columns (arrayref), remote_columns (arrayref), remote_table
1780 sub _table_fk_info { croak "ABSTRACT METHOD" }
1781
1782 # Returns an array of lower case table names
1783 sub _tables_list { croak "ABSTRACT METHOD" }
1784
1785 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1786 sub _dbic_stmt {
1787     my $self   = shift;
1788     my $class  = shift;
1789     my $method = shift;
1790
1791     # generate the pod for this statement, storing it with $self->_pod
1792     $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
1793
1794     my $args = dump(@_);
1795     $args = '(' . $args . ')' if @_ < 2;
1796     my $stmt = $method . $args . q{;};
1797
1798     warn qq|$class\->$stmt\n| if $self->debug;
1799     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1800     return;
1801 }
1802
1803 # generates the accompanying pod for a DBIC class method statement,
1804 # storing it with $self->_pod
1805 sub _make_pod {
1806     my $self   = shift;
1807     my $class  = shift;
1808     my $method = shift;
1809
1810     if ( $method eq 'table' ) {
1811         my ($table) = @_;
1812         my $pcm = $self->pod_comment_mode;
1813         my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
1814         $comment = $self->__table_comment($table);
1815         $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1816         $comment_in_name   = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1817         $comment_in_desc   = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
1818         $self->_pod( $class, "=head1 NAME" );
1819         my $table_descr = $class;
1820         $table_descr .= " - " . $comment if $comment and $comment_in_name;
1821         $self->{_class2table}{ $class } = $table;
1822         $self->_pod( $class, $table_descr );
1823         if ($comment and $comment_in_desc) {
1824             $self->_pod( $class, "=head1 DESCRIPTION" );
1825             $self->_pod( $class, $comment );
1826         }
1827         $self->_pod_cut( $class );
1828     } elsif ( $method eq 'add_columns' ) {
1829         $self->_pod( $class, "=head1 ACCESSORS" );
1830         my $col_counter = 0;
1831         my @cols = @_;
1832         while( my ($name,$attrs) = splice @cols,0,2 ) {
1833             $col_counter++;
1834             $self->_pod( $class, '=head2 ' . $name  );
1835             $self->_pod( $class,
1836                 join "\n", map {
1837                     my $s = $attrs->{$_};
1838                     $s = !defined $s          ? 'undef'             :
1839                         length($s) == 0       ? '(empty string)'    :
1840                         ref($s) eq 'SCALAR'   ? $$s                 :
1841                         ref($s)               ? dumper_squashed $s  :
1842                         looks_like_number($s) ? $s                  : qq{'$s'};
1843
1844                     "  $_: $s"
1845                  } sort keys %$attrs,
1846             );
1847             if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
1848                 $self->_pod( $class, $comment );
1849             }
1850         }
1851         $self->_pod_cut( $class );
1852     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1853         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1854         my ( $accessor, $rel_class ) = @_;
1855         $self->_pod( $class, "=head2 $accessor" );
1856         $self->_pod( $class, 'Type: ' . $method );
1857         $self->_pod( $class, "Related object: L<$rel_class>" );
1858         $self->_pod_cut( $class );
1859         $self->{_relations_started} { $class } = 1;
1860     }
1861 }
1862
1863 sub _filter_comment {
1864     my ($self, $txt) = @_;
1865
1866     $txt = '' if not defined $txt;
1867
1868     $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
1869
1870     return $txt;
1871 }
1872
1873 sub __table_comment {
1874     my $self = shift;
1875
1876     if (my $code = $self->can('_table_comment')) {
1877         return $self->_filter_comment($self->$code(@_));
1878     }
1879     
1880     return '';
1881 }
1882
1883 sub __column_comment {
1884     my $self = shift;
1885
1886     if (my $code = $self->can('_column_comment')) {
1887         return $self->_filter_comment($self->$code(@_));
1888     }
1889
1890     return '';
1891 }
1892
1893 # Stores a POD documentation
1894 sub _pod {
1895     my ($self, $class, $stmt) = @_;
1896     $self->_raw_stmt( $class, "\n" . $stmt  );
1897 }
1898
1899 sub _pod_cut {
1900     my ($self, $class ) = @_;
1901     $self->_raw_stmt( $class, "\n=cut\n" );
1902 }
1903
1904 # Store a raw source line for a class (for dumping purposes)
1905 sub _raw_stmt {
1906     my ($self, $class, $stmt) = @_;
1907     push(@{$self->{_dump_storage}->{$class}}, $stmt);
1908 }
1909
1910 # Like above, but separately for the externally loaded stuff
1911 sub _ext_stmt {
1912     my ($self, $class, $stmt) = @_;
1913     push(@{$self->{_ext_storage}->{$class}}, $stmt);
1914 }
1915
1916 sub _quote_table_name {
1917     my ($self, $table) = @_;
1918
1919     my $qt = $self->schema->storage->sql_maker->quote_char;
1920
1921     return $table unless $qt;
1922
1923     if (ref $qt) {
1924         return $qt->[0] . $table . $qt->[1];
1925     }
1926
1927     return $qt . $table . $qt;
1928 }
1929
1930 sub _custom_column_info {
1931     my ( $self, $table_name, $column_name, $column_info ) = @_;
1932
1933     if (my $code = $self->custom_column_info) {
1934         return $code->($table_name, $column_name, $column_info) || {};
1935     }
1936     return {};
1937 }
1938
1939 sub _datetime_column_info {
1940     my ( $self, $table_name, $column_name, $column_info ) = @_;
1941     my $result = {};
1942     my $type = $column_info->{data_type} || '';
1943     if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
1944             or ($type =~ /date|timestamp/i)) {
1945         $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
1946         $result->{locale}   = $self->datetime_locale   if $self->datetime_locale;
1947     }
1948     return $result;
1949 }
1950
1951 sub _lc {
1952     my ($self, $name) = @_;
1953
1954     return $self->preserve_case ? $name : lc($name);
1955 }
1956
1957 sub _uc {
1958     my ($self, $name) = @_;
1959
1960     return $self->preserve_case ? $name : uc($name);
1961 }
1962
1963 sub _unregister_source_for_table {
1964     my ($self, $table) = @_;
1965
1966     eval {
1967         local $@;
1968         my $schema = $self->schema;
1969         # in older DBIC it's a private method
1970         my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
1971         $schema->$unregister($self->_table2moniker($table));
1972         delete $self->monikers->{$table};
1973         delete $self->classes->{$table};
1974         delete $self->_upgrading_classes->{$table};
1975         delete $self->{_tables}{$table};
1976     };
1977 }
1978
1979 # remove the dump dir from @INC on destruction
1980 sub DESTROY {
1981     my $self = shift;
1982
1983     @INC = grep $_ ne $self->dump_directory, @INC;
1984 }
1985
1986 =head2 monikers
1987
1988 Returns a hashref of loaded table to moniker mappings.  There will
1989 be two entries for each table, the original name and the "normalized"
1990 name, in the case that the two are different (such as databases
1991 that like uppercase table names, or preserve your original mixed-case
1992 definitions, or what-have-you).
1993
1994 =head2 classes
1995
1996 Returns a hashref of table to class mappings.  In some cases it will
1997 contain multiple entries per table for the original and normalized table
1998 names, as above in L</monikers>.
1999
2000 =head1 COLUMN ACCESSOR COLLISIONS
2001
2002 Occasionally you may have a column name that collides with a perl method, such
2003 as C<can>. In such cases, the default action is to set the C<accessor> of the
2004 column spec to C<undef>.
2005
2006 You can then name the accessor yourself by placing code such as the following
2007 below the md5:
2008
2009     __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2010
2011 Another option is to use the L</col_collision_map> option.
2012
2013 =head1 SEE ALSO
2014
2015 L<DBIx::Class::Schema::Loader>
2016
2017 =head1 AUTHOR
2018
2019 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2020
2021 =head1 LICENSE
2022
2023 This library is free software; you can redistribute it and/or modify it under
2024 the same terms as Perl itself.
2025
2026 =cut
2027
2028 1;
2029 # vim:et sts=4 sw=4 tw=0: