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