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