use connection hack only for schema_base_class
[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 'dump';
10 use POSIX ();
11 use File::Spec ();
12 use Cwd ();
13 use Digest::MD5 ();
14 use Lingua::EN::Inflect::Number ();
15 use Lingua::EN::Inflect::Phrase ();
16 use String::ToIdentifier::EN ();
17 use String::ToIdentifier::EN::Unicode ();
18 use File::Temp ();
19 use Class::Unload;
20 use Class::Inspector ();
21 use Scalar::Util 'looks_like_number';
22 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_package_without_redefine_warnings class_path slurp_file/;
23 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
24 use Try::Tiny;
25 use DBIx::Class ();
26 use Encode qw/encode decode/;
27 use List::MoreUtils qw/all firstidx/;
28 use IPC::Open2;
29 use Symbol 'gensym';
30 use namespace::clean;
31
32 our $VERSION = '0.07010';
33
34 __PACKAGE__->mk_group_ro_accessors('simple', qw/
35                                 schema
36                                 schema_class
37
38                                 exclude
39                                 constraint
40                                 additional_classes
41                                 additional_base_classes
42                                 left_base_classes
43                                 components
44                                 schema_components
45                                 skip_relationships
46                                 skip_load_external
47                                 moniker_map
48                                 col_accessor_map
49                                 custom_column_info
50                                 inflect_singular
51                                 inflect_plural
52                                 debug
53                                 dump_directory
54                                 dump_overwrite
55                                 really_erase_my_files
56                                 resultset_namespace
57                                 default_resultset_class
58                                 schema_base_class
59                                 result_base_class
60                                 result_roles
61                                 use_moose
62                                 overwrite_modifications
63
64                                 relationship_attrs
65
66                                 _tables
67                                 classes
68                                 _upgrading_classes
69                                 monikers
70                                 dynamic
71                                 naming
72                                 datetime_timezone
73                                 datetime_locale
74                                 config_file
75                                 loader_class
76                                 table_comments_table
77                                 column_comments_table
78                                 class_to_table
79                                 moniker_to_table
80                                 uniq_to_primary
81                                 quiet
82 /);
83
84
85 __PACKAGE__->mk_group_accessors('simple', qw/
86                                 version_to_dump
87                                 schema_version_to_dump
88                                 _upgrading_from
89                                 _upgrading_from_load_classes
90                                 _downgrading_to_load_classes
91                                 _rewriting_result_namespace
92                                 use_namespaces
93                                 result_namespace
94                                 generate_pod
95                                 pod_comment_mode
96                                 pod_comment_spillover_length
97                                 preserve_case
98                                 col_collision_map
99                                 rel_collision_map
100                                 rel_name_map
101                                 real_dump_directory
102                                 result_components_map
103                                 result_roles_map
104                                 datetime_undef_if_invalid
105                                 _result_class_methods
106                                 naming_set
107                                 filter_generated_code
108                                 db_schema
109                                 qualify_objects
110                                 moniker_parts
111 /);
112
113 my $CURRENT_V = 'v7';
114
115 my @CLASS_ARGS = qw(
116     schema_components schema_base_class result_base_class
117     additional_base_classes left_base_classes additional_classes components
118     result_roles
119 );
120
121 my $CR   = "\x0d";
122 my $LF   = "\x0a";
123 my $CRLF = "\x0d\x0a";
124
125 =head1 NAME
126
127 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
128
129 =head1 SYNOPSIS
130
131 See L<DBIx::Class::Schema::Loader>.
132
133 =head1 DESCRIPTION
134
135 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
136 classes, and implements the common functionality between them.
137
138 =head1 CONSTRUCTOR OPTIONS
139
140 These constructor options are the base options for
141 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
142
143 =head2 skip_relationships
144
145 Skip setting up relationships.  The default is to attempt the loading
146 of relationships.
147
148 =head2 skip_load_external
149
150 Skip loading of other classes in @INC. The default is to merge all other classes
151 with the same name found in @INC into the schema file we are creating.
152
153 =head2 naming
154
155 Static schemas (ones dumped to disk) will, by default, use the new-style
156 relationship names and singularized Results, unless you're overwriting an
157 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
158 which case the backward compatible RelBuilder will be activated, and the
159 appropriate monikerization used.
160
161 Specifying
162
163     naming => 'current'
164
165 will disable the backward-compatible RelBuilder and use
166 the new-style relationship names along with singularized Results, even when
167 overwriting a dump made with an earlier version.
168
169 The option also takes a hashref:
170
171     naming => {
172         relationships    => 'v8',
173         monikers         => 'v8',
174         column_accessors => 'v8',
175         force_ascii      => 1,
176     }
177
178 or
179
180     naming => { ALL => 'v8', force_ascii => 1 }
181
182 The keys are:
183
184 =over 4
185
186 =item ALL
187
188 Set L</relationships>, L</monikers> and L</column_accessors> to the specified
189 value.
190
191 =item relationships
192
193 How to name relationship accessors.
194
195 =item monikers
196
197 How to name Result classes.
198
199 =item column_accessors
200
201 How to name column accessors in Result classes.
202
203 =item force_ascii
204
205 For L</v8> mode and later, uses L<String::ToIdentifier::EN> instead of
206 L<String::ToIdentifier::EM::Unicode> to force monikers and other identifiers to
207 ASCII.
208
209 =back
210
211 The values can be:
212
213 =over 4
214
215 =item current
216
217 Latest style, whatever that happens to be.
218
219 =item v4
220
221 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
222
223 =item v5
224
225 Monikers singularized as whole words, C<might_have> relationships for FKs on
226 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
227
228 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
229 the v5 RelBuilder.
230
231 =item v6
232
233 All monikers and relationships are inflected using
234 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
235 from relationship names.
236
237 In general, there is very little difference between v5 and v6 schemas.
238
239 =item v7
240
241 This mode is identical to C<v6> mode, except that monikerization of CamelCase
242 table names is also done correctly.
243
244 CamelCase column names in case-preserving mode will also be handled correctly
245 for relationship name inflection. See L</preserve_case>.
246
247 In this mode, CamelCase L</column_accessors> are normalized based on case
248 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
249
250 If you don't have any CamelCase table or column names, you can upgrade without
251 breaking any of your code.
252
253 =item v8
254
255 (EXPERIMENTAL)
256
257 The default mode is L</v7>, to get L</v8> mode, you have to specify it in
258 L</naming> explictly until C<0.08> comes out.
259
260 L</monikers> and L</column_accessors> are created using
261 L<String::ToIdentifier::EN::Unicode> or L<String::ToIdentifier::EN> if
262 L</force_ascii> is set; this is only significant for names with non-C<\w>
263 characters such as C<.>.
264
265 For relationships, belongs_to accessors are made from column names by stripping
266 postfixes other than C<_id> as well, just C<id>, C<_?ref>, C<_?cd>, C<_?code>
267 and C<_num>.
268
269 =item preserve
270
271 For L</monikers>, this option does not inflect the table names but makes
272 monikers based on the actual name. For L</column_accessors> this option does
273 not normalize CamelCase column names to lowercase column accessors, but makes
274 accessors that are the same names as the columns (with any non-\w chars
275 replaced with underscores.)
276
277 =item singular
278
279 For L</monikers>, singularizes the names using the most current inflector. This
280 is the same as setting the option to L</current>.
281
282 =item plural
283
284 For L</monikers>, pluralizes the names, using the most current inflector.
285
286 =back
287
288 Dynamic schemas will always default to the 0.04XXX relationship names and won't
289 singularize Results for backward compatibility, to activate the new RelBuilder
290 and singularization put this in your C<Schema.pm> file:
291
292     __PACKAGE__->naming('current');
293
294 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
295 next major version upgrade:
296
297     __PACKAGE__->naming('v7');
298
299 =head2 quiet
300
301 If true, will not print the usual C<Dumping manual schema ... Schema dump
302 completed.> messages. Does not affect warnings (except for warnings related to
303 L</really_erase_my_files>.)
304
305 =head2 generate_pod
306
307 By default POD will be generated for columns and relationships, using database
308 metadata for the text if available and supported.
309
310 Comment metadata can be stored in two ways.
311
312 The first is that you can create two tables named C<table_comments> and
313 C<column_comments> respectively. These tables must exist in the same database
314 and schema as the tables they describe. They both need to have columns named
315 C<table_name> and C<comment_text>. The second one needs to have a column named
316 C<column_name>. Then data stored in these tables will be used as a source of
317 metadata about tables and comments.
318
319 (If you wish you can change the name of these tables with the parameters
320 L</table_comments_table> and L</column_comments_table>.)
321
322 As a fallback you can use built-in commenting mechanisms.  Currently this is
323 only supported for PostgreSQL, Oracle and MySQL.  To create comments in
324 PostgreSQL you add statements of the form C<COMMENT ON TABLE some_table IS
325 '...'>, the same syntax is used in Oracle. To create comments in MySQL you add
326 C<COMMENT '...'> to the end of the column or table definition.  Note that MySQL
327 restricts the length of comments, and also does not handle complex Unicode
328 characters properly.
329
330 Set this to C<0> to turn off all POD generation.
331
332 =head2 pod_comment_mode
333
334 Controls where table comments appear in the generated POD. Smaller table
335 comments are appended to the C<NAME> section of the documentation, and larger
336 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
337 section to be generated with the comment always, only use C<NAME>, or choose
338 the length threshold at which the comment is forced into the description.
339
340 =over 4
341
342 =item name
343
344 Use C<NAME> section only.
345
346 =item description
347
348 Force C<DESCRIPTION> always.
349
350 =item auto
351
352 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
353 default.
354
355 =back
356
357 =head2 pod_comment_spillover_length
358
359 When pod_comment_mode is set to C<auto>, this is the length of the comment at
360 which it will be forced into a separate description section.
361
362 The default is C<60>
363
364 =head2 table_comments_table
365
366 The table to look for comments about tables in.  By default C<table_comments>.
367 See L</generate_pod> for details.
368
369 This must not be a fully qualified name, the table will be looked for in the
370 same database and schema as the table whose comment is being retrieved.
371
372 =head2 column_comments_table
373
374 The table to look for comments about columns in.  By default C<column_comments>.
375 See L</generate_pod> for details.
376
377 This must not be a fully qualified name, the table will be looked for in the
378 same database and schema as the table/column whose comment is being retrieved.
379
380 =head2 relationship_attrs
381
382 Hashref of attributes to pass to each generated relationship, listed
383 by type.  Also supports relationship type 'all', containing options to
384 pass to all generated relationships.  Attributes set for more specific
385 relationship types override those set in 'all'.
386
387 For example:
388
389   relationship_attrs => {
390     belongs_to => { is_deferrable => 0 },
391   },
392
393 use this to turn off DEFERRABLE on your foreign key constraints.
394
395 =head2 debug
396
397 If set to true, each constructive L<DBIx::Class> statement the loader
398 decides to execute will be C<warn>-ed before execution.
399
400 =head2 db_schema
401
402 Set the name of the schema to load (schema in the sense that your database
403 vendor means it).
404
405 Can be set to an arrayref of schema names for multiple schemas, or the special
406 value C<%> for all schemas.
407
408 For MSSQL, Sybase ASE, and Informix can be set to a hashref of databases as
409 keys and arrays of owners as values, set to the value:
410
411     { '%' => '%' }
412
413 for all owners in all databases.
414
415 You may need to control naming of monikers with L</moniker_parts> if you have
416 name clashes for tables in different schemas/databases.
417
418 =head2 moniker_parts
419
420 The database table names are represented by the
421 L<DBIx::Class::Schema::Loader::Table> class in the loader, the
422 L<DBIx::Class::Schema::Loader::Table::Sybase> class for Sybase ASE and
423 L<DBIx::Class::Schema::Loader::Table::Informix> for Informix.
424
425 Monikers are created normally based on just the
426 L<name|DBIx::Class::Schema::Loader::DBObject/name> property, corresponding to
427 the table name, but can consist of other parts of the fully qualified name of
428 the table.
429
430 The L</moniker_parts> option is an arrayref of methods on the table class
431 corresponding to parts of the fully qualified table name, defaulting to
432 C<['name']>, in the order those parts are used to create the moniker name.
433
434 The C<'name'> entry B<must> be present.
435
436 Below is a table of supported databases and possible L</moniker_parts>.
437
438 =over 4
439
440 =item * DB2, Firebird, mysql, Oracle, Pg, SQLAnywhere, SQLite, MS Access
441
442 C<schema>, C<name>
443
444 =item * Informix, MSSQL, Sybase ASE
445
446 C<database>, C<schema>, C<name>    
447
448 =back
449
450 =head2 constraint
451
452 Only load tables matching regex.  Best specified as a qr// regex.
453
454 =head2 exclude
455
456 Exclude tables matching regex.  Best specified as a qr// regex.
457
458 =head2 moniker_map
459
460 Overrides the default table name to moniker translation.  Can be either
461 a hashref of table keys and moniker values, or a coderef for a translator
462 function taking a single scalar table name argument and returning
463 a scalar moniker.  If the hash entry does not exist, or the function
464 returns a false value, the code falls back to default behavior
465 for that table name.
466
467 The default behavior is to split on case transition and non-alphanumeric
468 boundaries, singularize the resulting phrase, then join the titlecased words
469 together. Examples:
470
471     Table Name       | Moniker Name
472     ---------------------------------
473     luser            | Luser
474     luser_group      | LuserGroup
475     luser-opts       | LuserOpt
476     stations_visited | StationVisited
477     routeChange      | RouteChange
478
479 =head2 col_accessor_map
480
481 Same as moniker_map, but for column accessor names.  If a coderef is
482 passed, the code is called with arguments of
483
484    the name of the column in the underlying database,
485    default accessor name that DBICSL would ordinarily give this column,
486    {
487       table_class     => name of the DBIC class we are building,
488       table_moniker   => calculated moniker for this table (after moniker_map if present),
489       table_name      => name of the database table,
490       full_table_name => schema-qualified name of the database table (RDBMS specific),
491       schema_class    => name of the schema class we are building,
492       column_info     => hashref of column info (data_type, is_nullable, etc),
493     }
494
495 =head2 rel_name_map
496
497 Similar in idea to moniker_map, but different in the details.  It can be
498 a hashref or a code ref.
499
500 If it is a hashref, keys can be either the default relationship name, or the
501 moniker. The keys that are the default relationship name should map to the
502 name you want to change the relationship to. Keys that are monikers should map
503 to hashes mapping relationship names to their translation.  You can do both at
504 once, and the more specific moniker version will be picked up first.  So, for
505 instance, you could have
506
507     {
508         bar => "baz",
509         Foo => {
510             bar => "blat",
511         },
512     }
513
514 and relationships that would have been named C<bar> will now be named C<baz>
515 except that in the table whose moniker is C<Foo> it will be named C<blat>.
516
517 If it is a coderef, the argument passed will be a hashref of this form:
518
519     {
520         name           => default relationship name,
521         type           => the relationship type eg: C<has_many>,
522         local_class    => name of the DBIC class we are building,
523         local_moniker  => moniker of the DBIC class we are building,
524         local_columns  => columns in this table in the relationship,
525         remote_class   => name of the DBIC class we are related to,
526         remote_moniker => moniker of the DBIC class we are related to,
527         remote_columns => columns in the other table in the relationship,
528     }
529
530 DBICSL will try to use the value returned as the relationship name.
531
532 =head2 inflect_plural
533
534 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
535 if hash key does not exist or coderef returns false), but acts as a map
536 for pluralizing relationship names.  The default behavior is to utilize
537 L<Lingua::EN::Inflect::Phrase/to_PL>.
538
539 =head2 inflect_singular
540
541 As L</inflect_plural> above, but for singularizing relationship names.
542 Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
543
544 =head2 schema_base_class
545
546 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
547
548 B<WARNING>: if you define schema_base_class for a dynamic schema, you cannot
549 define a L<connection|DBIx::Class::Schema/connection> method in your schema
550 class, it must be in the schema base class, due to the limits of L<mro>.
551
552 =head2 schema_components
553
554 List of components to load into the Schema class.
555
556 B<WARNING>: if you define schema_components for a dynamic schema, you cannot
557 define a L<connection|DBIx::Class::Schema/connection> method in your schema
558 class, it must be in L</schema_base_class> or a component, due to the limits of
559 L<mro>.
560
561 =head2 result_base_class
562
563 Base class for your table classes (aka result classes). Defaults to
564 'DBIx::Class::Core'.
565
566 =head2 additional_base_classes
567
568 List of additional base classes all of your table classes will use.
569
570 =head2 left_base_classes
571
572 List of additional base classes all of your table classes will use
573 that need to be leftmost.
574
575 =head2 additional_classes
576
577 List of additional classes which all of your table classes will use.
578
579 =head2 components
580
581 List of additional components to be loaded into all of your Result
582 classes.  A good example would be
583 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
584
585 =head2 result_components_map
586
587 A hashref of moniker keys and component values.  Unlike L</components>, which
588 loads the given components into every Result class, this option allows you to
589 load certain components for specified Result classes. For example:
590
591   result_components_map => {
592       StationVisited => '+YourApp::Schema::Component::StationVisited',
593       RouteChange    => [
594                             '+YourApp::Schema::Component::RouteChange',
595                             'InflateColumn::DateTime',
596                         ],
597   }
598   
599 You may use this in conjunction with L</components>.
600
601 =head2 result_roles
602
603 List of L<Moose> roles to be applied to all of your Result classes.
604
605 =head2 result_roles_map
606
607 A hashref of moniker keys and role values.  Unlike L</result_roles>, which
608 applies the given roles to every Result class, this option allows you to apply
609 certain roles for specified Result classes. For example:
610
611   result_roles_map => {
612       StationVisited => [
613                             'YourApp::Role::Building',
614                             'YourApp::Role::Destination',
615                         ],
616       RouteChange    => 'YourApp::Role::TripEvent',
617   }
618   
619 You may use this in conjunction with L</result_roles>.
620
621 =head2 use_namespaces
622
623 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
624 a C<0>.
625
626 Generate result class names suitable for
627 L<DBIx::Class::Schema/load_namespaces> and call that instead of
628 L<DBIx::Class::Schema/load_classes>. When using this option you can also
629 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
630 C<resultset_namespace>, C<default_resultset_class>), and they will be added
631 to the call (and the generated result class names adjusted appropriately).
632
633 =head2 dump_directory
634
635 The value of this option is a perl libdir pathname.  Within
636 that directory this module will create a baseline manual
637 L<DBIx::Class::Schema> module set, based on what it creates at runtime.
638
639 The created schema class will have the same classname as the one on
640 which you are setting this option (and the ResultSource classes will be
641 based on this name as well).
642
643 Normally you wouldn't hard-code this setting in your schema class, as it
644 is meant for one-time manual usage.
645
646 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
647 recommended way to access this functionality.
648
649 =head2 dump_overwrite
650
651 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
652 the same thing as the old C<dump_overwrite> setting from previous releases.
653
654 =head2 really_erase_my_files
655
656 Default false.  If true, Loader will unconditionally delete any existing
657 files before creating the new ones from scratch when dumping a schema to disk.
658
659 The default behavior is instead to only replace the top portion of the
660 file, up to and including the final stanza which contains
661 C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
662 leaving any customizations you placed after that as they were.
663
664 When C<really_erase_my_files> is not set, if the output file already exists,
665 but the aforementioned final stanza is not found, or the checksum
666 contained there does not match the generated contents, Loader will
667 croak and not touch the file.
668
669 You should really be using version control on your schema classes (and all
670 of the rest of your code for that matter).  Don't blame me if a bug in this
671 code wipes something out when it shouldn't have, you've been warned.
672
673 =head2 overwrite_modifications
674
675 Default false.  If false, when updating existing files, Loader will
676 refuse to modify any Loader-generated code that has been modified
677 since its last run (as determined by the checksum Loader put in its
678 comment lines).
679
680 If true, Loader will discard any manual modifications that have been
681 made to Loader-generated code.
682
683 Again, you should be using version control on your schema classes.  Be
684 careful with this option.
685
686 =head2 custom_column_info
687
688 Hook for adding extra attributes to the
689 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
690
691 Must be a coderef that returns a hashref with the extra attributes.
692
693 Receives the table name, column name and column_info.
694
695 For example:
696
697   custom_column_info => sub {
698       my ($table_name, $column_name, $column_info) = @_;
699
700       if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
701           return { is_snoopy => 1 };
702       }
703   },
704
705 This attribute can also be used to set C<inflate_datetime> on a non-datetime
706 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
707
708 =head2 datetime_timezone
709
710 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
711 columns with the DATE/DATETIME/TIMESTAMP data_types.
712
713 =head2 datetime_locale
714
715 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
716 columns with the DATE/DATETIME/TIMESTAMP data_types.
717
718 =head2 datetime_undef_if_invalid
719
720 Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
721 datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
722 TIMESTAMP columns.
723
724 The default is recommended to deal with data such as C<00/00/00> which
725 sometimes ends up in such columns in MySQL.
726
727 =head2 config_file
728
729 File in Perl format, which should return a HASH reference, from which to read
730 loader options.
731
732 =head2 preserve_case
733
734 Usually column names are lowercased, to make them easier to work with in
735 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
736 supports it.
737
738 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
739 case-sensitive collation will turn this option on unconditionally.
740
741 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
742 setting this option.
743
744 =head2 qualify_objects
745
746 Set to true to prepend the L</db_schema> to table names for C<<
747 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
748
749 =head2 use_moose
750
751 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
752 L<namespace::autoclean>. The default content after the md5 sum also makes the
753 classes immutable.
754
755 It is safe to upgrade your existing Schema to this option.
756
757 =head2 col_collision_map
758
759 This option controls how accessors for column names which collide with perl
760 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
761
762 This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
763 strings which are compiled to regular expressions that map to
764 L<sprintf|perlfunc/sprintf> formats.
765
766 Examples:
767
768     col_collision_map => 'column_%s'
769
770     col_collision_map => { '(.*)' => 'column_%s' }
771
772     col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
773
774 =head2 rel_collision_map
775
776 Works just like L</col_collision_map>, but for relationship names/accessors
777 rather than column names/accessors.
778
779 The default is to just append C<_rel> to the relationship name, see
780 L</RELATIONSHIP NAME COLLISIONS>.
781
782 =head2 uniq_to_primary
783
784 Automatically promotes the largest unique constraints with non-nullable columns
785 on tables to primary keys, assuming there is only one largest unique
786 constraint.
787
788 =head2 filter_generated_code
789
790 An optional hook that lets you filter the generated text for various classes
791 through a function that change it in any way that you want.  The function will
792 receive the type of file, C<schema> or C<result>, class and code; and returns
793 the new code to use instead.  For instance you could add custom comments, or do
794 anything else that you want.
795
796 The option can also be set to a string, which is then used as a filter program,
797 e.g. C<perltidy>.
798
799 If this exists but fails to return text matching C</\bpackage\b/>, no file will
800 be generated.
801
802     filter_generated_code => sub {
803         my ($type, $class, $text) = @_;
804         ...
805         return $new_code;
806     }
807
808 =head1 METHODS
809
810 None of these methods are intended for direct invocation by regular
811 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
812 L<DBIx::Class::Schema::Loader>.
813
814 =cut
815
816 # ensure that a peice of object data is a valid arrayref, creating
817 # an empty one or encapsulating whatever's there.
818 sub _ensure_arrayref {
819     my $self = shift;
820
821     foreach (@_) {
822         $self->{$_} ||= [];
823         $self->{$_} = [ $self->{$_} ]
824             unless ref $self->{$_} eq 'ARRAY';
825     }
826 }
827
828 =head2 new
829
830 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
831 by L<DBIx::Class::Schema::Loader>.
832
833 =cut
834
835 sub new {
836     my ( $class, %args ) = @_;
837
838     if (exists $args{column_accessor_map}) {
839         $args{col_accessor_map} = delete $args{column_accessor_map};
840     }
841
842     my $self = { %args };
843
844     # don't lose undef options
845     for (values %$self) {
846         $_ = 0 unless defined $_;
847     }
848
849     bless $self => $class;
850
851     if (my $config_file = $self->config_file) {
852         my $config_opts = do $config_file;
853
854         croak "Error reading config from $config_file: $@" if $@;
855
856         croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
857
858         while (my ($k, $v) = each %$config_opts) {
859             $self->{$k} = $v unless exists $self->{$k};
860         }
861     }
862
863     if (defined $self->{result_component_map}) {
864         if (defined $self->result_components_map) {
865             croak "Specify only one of result_components_map or result_component_map";
866         }
867         $self->result_components_map($self->{result_component_map})
868     }
869     
870     if (defined $self->{result_role_map}) {
871         if (defined $self->result_roles_map) {
872             croak "Specify only one of result_roles_map or result_role_map";
873         }
874         $self->result_roles_map($self->{result_role_map})
875     }
876
877     croak "the result_roles and result_roles_map options may only be used in conjunction with use_moose=1"
878         if ((not defined $self->use_moose) || (not $self->use_moose))
879             && ((defined $self->result_roles) || (defined $self->result_roles_map));
880
881     $self->_ensure_arrayref(qw/schema_components
882                                additional_classes
883                                additional_base_classes
884                                left_base_classes
885                                components
886                                result_roles
887                               /);
888
889     $self->_validate_class_args;
890
891     croak "result_components_map must be a hash"
892         if defined $self->result_components_map
893             && ref $self->result_components_map ne 'HASH';
894
895     if ($self->result_components_map) {
896         my %rc_map = %{ $self->result_components_map };
897         foreach my $moniker (keys %rc_map) {
898             $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
899         }
900         $self->result_components_map(\%rc_map);
901     }
902     else {
903         $self->result_components_map({});
904     }
905     $self->_validate_result_components_map;
906
907     croak "result_roles_map must be a hash"
908         if defined $self->result_roles_map
909             && ref $self->result_roles_map ne 'HASH';
910
911     if ($self->result_roles_map) {
912         my %rr_map = %{ $self->result_roles_map };
913         foreach my $moniker (keys %rr_map) {
914             $rr_map{$moniker} = [ $rr_map{$moniker} ] unless ref $rr_map{$moniker};
915         }
916         $self->result_roles_map(\%rr_map);
917     } else {
918         $self->result_roles_map({});
919     }
920     $self->_validate_result_roles_map;
921
922     if ($self->use_moose) {
923         if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
924             die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
925                 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
926         }
927     }
928
929     $self->{_tables} = {};
930     $self->{monikers} = {};
931     $self->{moniker_to_table} = {};
932     $self->{class_to_table} = {};
933     $self->{classes}  = {};
934     $self->{_upgrading_classes} = {};
935
936     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
937     $self->{schema} ||= $self->{schema_class};
938     $self->{table_comments_table} ||= 'table_comments';
939     $self->{column_comments_table} ||= 'column_comments';
940
941     croak "dump_overwrite is deprecated.  Please read the"
942         . " DBIx::Class::Schema::Loader::Base documentation"
943             if $self->{dump_overwrite};
944
945     $self->{dynamic} = ! $self->{dump_directory};
946     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
947                                                      TMPDIR  => 1,
948                                                      CLEANUP => 1,
949                                                    );
950
951     $self->{dump_directory} ||= $self->{temp_directory};
952
953     $self->real_dump_directory($self->{dump_directory});
954
955     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
956     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
957
958     if (not defined $self->naming) {
959         $self->naming_set(0);
960     }
961     else {
962         $self->naming_set(1);
963     }
964
965     if ((not ref $self->naming) && defined $self->naming) {
966         my $naming_ver = $self->naming;
967         $self->{naming} = {
968             relationships => $naming_ver,
969             monikers => $naming_ver,
970             column_accessors => $naming_ver,
971         };
972     }
973     elsif (ref $self->naming eq 'HASH' && exists $self->naming->{ALL}) {
974         my $val = delete $self->naming->{ALL};
975
976         $self->naming->{$_} = $val
977             foreach qw/relationships monikers column_accessors/;
978     }
979
980     if ($self->naming) {
981         foreach my $key (qw/relationships monikers column_accessors/) {
982             $self->naming->{$key} = $CURRENT_V if $self->naming->{$key} eq 'current';
983         }
984     }
985     $self->{naming} ||= {};
986
987     if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
988         croak 'custom_column_info must be a CODE ref';
989     }
990
991     $self->_check_back_compat;
992
993     $self->use_namespaces(1) unless defined $self->use_namespaces;
994     $self->generate_pod(1)   unless defined $self->generate_pod;
995     $self->pod_comment_mode('auto')         unless defined $self->pod_comment_mode;
996     $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
997
998     if (my $col_collision_map = $self->col_collision_map) {
999         if (my $reftype = ref $col_collision_map) {
1000             if ($reftype ne 'HASH') {
1001                 croak "Invalid type $reftype for option 'col_collision_map'";
1002             }
1003         }
1004         else {
1005             $self->col_collision_map({ '(.*)' => $col_collision_map });
1006         }
1007     }
1008
1009     if (my $rel_collision_map = $self->rel_collision_map) {
1010         if (my $reftype = ref $rel_collision_map) {
1011             if ($reftype ne 'HASH') {
1012                 croak "Invalid type $reftype for option 'rel_collision_map'";
1013             }
1014         }
1015         else {
1016             $self->rel_collision_map({ '(.*)' => $rel_collision_map });
1017         }
1018     }
1019
1020     if (defined(my $rel_name_map = $self->rel_name_map)) {
1021         my $reftype = ref $rel_name_map;
1022         if ($reftype ne 'HASH' && $reftype ne 'CODE') {
1023             croak "Invalid type $reftype for option 'rel_name_map', must be HASH or CODE";
1024         }
1025     }
1026
1027     if (defined(my $filter = $self->filter_generated_code)) {
1028         my $reftype = ref $filter;
1029         if ($reftype && $reftype ne 'CODE') {
1030             croak "Invalid type $reftype for option 'filter_generated_code, must be a scalar or a CODE reference";
1031         }
1032     }
1033
1034     if (defined $self->db_schema) {
1035         if (ref $self->db_schema eq 'ARRAY') {
1036             if (@{ $self->db_schema } > 1) {
1037                 $self->{qualify_objects} = 1;
1038             }
1039             elsif (@{ $self->db_schema } == 0) {
1040                 $self->{db_schema} = undef;
1041             }
1042         }
1043         elsif (not ref $self->db_schema) {
1044             if ($self->db_schema eq '%') {
1045                 $self->{qualify_objects} = 1;
1046             }
1047
1048             $self->{db_schema} = [ $self->db_schema ];
1049         }
1050     }
1051
1052     if (not $self->moniker_parts) {
1053         $self->moniker_parts(['name']);
1054     }
1055     else {
1056         if (not ref $self->moniker_parts) {
1057             $self->moniker_parts([ $self->moniker_parts ]);
1058         }
1059         if (ref $self->moniker_parts ne 'ARRAY') {
1060             croak 'moniker_parts must be an arrayref';
1061         }
1062         if ((firstidx { $_ eq 'name' } @{ $self->moniker_parts }) == -1) {
1063             croak "moniker_parts option *must* contain 'name'";
1064         }
1065     }
1066
1067     return $self;
1068 }
1069
1070 sub _check_back_compat {
1071     my ($self) = @_;
1072
1073 # dynamic schemas will always be in 0.04006 mode, unless overridden
1074     if ($self->dynamic) {
1075 # just in case, though no one is likely to dump a dynamic schema
1076         $self->schema_version_to_dump('0.04006');
1077
1078         if (not $self->naming_set) {
1079             warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1080
1081 Dynamic schema detected, will run in 0.04006 mode.
1082
1083 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
1084 to disable this warning.
1085
1086 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
1087 details.
1088 EOF
1089         }
1090         else {
1091             $self->_upgrading_from('v4');
1092         }
1093
1094         if ((not defined $self->use_namespaces) && ($self->naming_set)) {
1095             $self->use_namespaces(1);
1096         }
1097
1098         $self->naming->{relationships} ||= 'v4';
1099         $self->naming->{monikers}      ||= 'v4';
1100
1101         if ($self->use_namespaces) {
1102             $self->_upgrading_from_load_classes(1);
1103         }
1104         else {
1105             $self->use_namespaces(0);
1106         }
1107
1108         return;
1109     }
1110
1111 # otherwise check if we need backcompat mode for a static schema
1112     my $filename = $self->get_dump_filename($self->schema_class);
1113     return unless -e $filename;
1114
1115     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
1116       $self->_parse_generated_file($filename);
1117
1118     return unless $old_ver;
1119
1120     # determine if the existing schema was dumped with use_moose => 1
1121     if (! defined $self->use_moose) {
1122         $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
1123     }
1124
1125     my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
1126
1127     my $result_namespace = do { ($old_gen =~ /result_namespace => (.+)/) ? $1 : '' };
1128     my $ds = eval $result_namespace;
1129     die <<"EOF" if $@;
1130 Could not eval expression '$result_namespace' for result_namespace from
1131 $filename: $@
1132 EOF
1133     $result_namespace = $ds || '';
1134
1135     if ($load_classes && (not defined $self->use_namespaces)) {
1136         warn <<"EOF"  unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1137
1138 'load_classes;' static schema detected, turning off 'use_namespaces'.
1139
1140 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
1141 variable to disable this warning.
1142
1143 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
1144 details.
1145 EOF
1146         $self->use_namespaces(0);
1147     }
1148     elsif ($load_classes && $self->use_namespaces) {
1149         $self->_upgrading_from_load_classes(1);
1150     }
1151     elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
1152         $self->_downgrading_to_load_classes(
1153             $result_namespace || 'Result'
1154         );
1155     }
1156     elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
1157         if (not $self->result_namespace) {
1158             $self->result_namespace($result_namespace || 'Result');
1159         }
1160         elsif ($result_namespace ne $self->result_namespace) {
1161             $self->_rewriting_result_namespace(
1162                 $result_namespace || 'Result'
1163             );
1164         }
1165     }
1166
1167     # XXX when we go past .0 this will need fixing
1168     my ($v) = $old_ver =~ /([1-9])/;
1169     $v = "v$v";
1170
1171     return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
1172
1173     if (not %{ $self->naming }) {
1174         warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1175
1176 Version $old_ver static schema detected, turning on backcompat mode.
1177
1178 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
1179 to disable this warning.
1180
1181 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
1182
1183 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
1184 from version 0.04006.
1185 EOF
1186
1187         $self->naming->{relationships}    ||= $v;
1188         $self->naming->{monikers}         ||= $v;
1189         $self->naming->{column_accessors} ||= $v;
1190
1191         $self->schema_version_to_dump($old_ver);
1192     }
1193     else {
1194         $self->_upgrading_from($v);
1195     }
1196 }
1197
1198 sub _validate_class_args {
1199     my $self = shift;
1200
1201     foreach my $k (@CLASS_ARGS) {
1202         next unless $self->$k;
1203
1204         my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
1205         $self->_validate_classes($k, \@classes);
1206     }
1207 }
1208
1209 sub _validate_result_components_map {
1210     my $self = shift;
1211
1212     foreach my $classes (values %{ $self->result_components_map }) {
1213         $self->_validate_classes('result_components_map', $classes);
1214     }
1215 }
1216
1217 sub _validate_result_roles_map {
1218     my $self = shift;
1219
1220     foreach my $classes (values %{ $self->result_roles_map }) {
1221         $self->_validate_classes('result_roles_map', $classes);
1222     }
1223 }
1224
1225 sub _validate_classes {
1226     my $self = shift;
1227     my $key  = shift;
1228     my $classes = shift;
1229
1230     # make a copy to not destroy original
1231     my @classes = @$classes;
1232
1233     foreach my $c (@classes) {
1234         # components default to being under the DBIx::Class namespace unless they
1235         # are preceeded with a '+'
1236         if ( $key =~ m/component/ && $c !~ s/^\+// ) {
1237             $c = 'DBIx::Class::' . $c;
1238         }
1239
1240         # 1 == installed, 0 == not installed, undef == invalid classname
1241         my $installed = Class::Inspector->installed($c);
1242         if ( defined($installed) ) {
1243             if ( $installed == 0 ) {
1244                 croak qq/$c, as specified in the loader option "$key", is not installed/;
1245             }
1246         } else {
1247             croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
1248         }
1249     }
1250 }
1251
1252
1253 sub _find_file_in_inc {
1254     my ($self, $file) = @_;
1255
1256     foreach my $prefix (@INC) {
1257         my $fullpath = File::Spec->catfile($prefix, $file);
1258         return $fullpath if -f $fullpath
1259             # abs_path throws on Windows for nonexistant files
1260             and (try { Cwd::abs_path($fullpath) }) ne
1261                ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
1262     }
1263
1264     return;
1265 }
1266
1267 sub _find_class_in_inc {
1268     my ($self, $class) = @_;
1269
1270     return $self->_find_file_in_inc(class_path($class));
1271 }
1272
1273 sub _rewriting {
1274     my $self = shift;
1275
1276     return $self->_upgrading_from
1277         || $self->_upgrading_from_load_classes
1278         || $self->_downgrading_to_load_classes
1279         || $self->_rewriting_result_namespace
1280     ;
1281 }
1282
1283 sub _rewrite_old_classnames {
1284     my ($self, $code) = @_;
1285
1286     return $code unless $self->_rewriting;
1287
1288     my %old_classes = reverse %{ $self->_upgrading_classes };
1289
1290     my $re = join '|', keys %old_classes;
1291     $re = qr/\b($re)\b/;
1292
1293     $code =~ s/$re/$old_classes{$1} || $1/eg;
1294
1295     return $code;
1296 }
1297
1298 sub _load_external {
1299     my ($self, $class) = @_;
1300
1301     return if $self->{skip_load_external};
1302
1303     # so that we don't load our own classes, under any circumstances
1304     local *INC = [ grep $_ ne $self->dump_directory, @INC ];
1305
1306     my $real_inc_path = $self->_find_class_in_inc($class);
1307
1308     my $old_class = $self->_upgrading_classes->{$class}
1309         if $self->_rewriting;
1310
1311     my $old_real_inc_path = $self->_find_class_in_inc($old_class)
1312         if $old_class && $old_class ne $class;
1313
1314     return unless $real_inc_path || $old_real_inc_path;
1315
1316     if ($real_inc_path) {
1317         # If we make it to here, we loaded an external definition
1318         warn qq/# Loaded external class definition for '$class'\n/
1319             if $self->debug;
1320
1321         my $code = $self->_rewrite_old_classnames(slurp_file $real_inc_path);
1322
1323         if ($self->dynamic) { # load the class too
1324             eval_package_without_redefine_warnings($class, $code);
1325         }
1326
1327         $self->_ext_stmt($class,
1328           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
1329          .qq|# They are now part of the custom portion of this file\n|
1330          .qq|# for you to hand-edit.  If you do not either delete\n|
1331          .qq|# this section or remove that file from \@INC, this section\n|
1332          .qq|# will be repeated redundantly when you re-create this\n|
1333          .qq|# file again via Loader!  See skip_load_external to disable\n|
1334          .qq|# this feature.\n|
1335         );
1336         chomp $code;
1337         $self->_ext_stmt($class, $code);
1338         $self->_ext_stmt($class,
1339             qq|# End of lines loaded from '$real_inc_path' |
1340         );
1341     }
1342
1343     if ($old_real_inc_path) {
1344         my $code = slurp_file $old_real_inc_path;
1345
1346         $self->_ext_stmt($class, <<"EOF");
1347
1348 # These lines were loaded from '$old_real_inc_path',
1349 # based on the Result class name that would have been created by an older
1350 # version of the Loader. For a static schema, this happens only once during
1351 # upgrade. See skip_load_external to disable this feature.
1352 EOF
1353
1354         $code = $self->_rewrite_old_classnames($code);
1355
1356         if ($self->dynamic) {
1357             warn <<"EOF";
1358
1359 Detected external content in '$old_real_inc_path', a class name that would have
1360 been used by an older version of the Loader.
1361
1362 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
1363 new name of the Result.
1364 EOF
1365             eval_package_without_redefine_warnings($class, $code);
1366         }
1367
1368         chomp $code;
1369         $self->_ext_stmt($class, $code);
1370         $self->_ext_stmt($class,
1371             qq|# End of lines loaded from '$old_real_inc_path' |
1372         );
1373     }
1374 }
1375
1376 =head2 load
1377
1378 Does the actual schema-construction work.
1379
1380 =cut
1381
1382 sub load {
1383     my $self = shift;
1384
1385     $self->_load_tables(
1386         $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1387     );
1388 }
1389
1390 =head2 rescan
1391
1392 Arguments: schema
1393
1394 Rescan the database for changes. Returns a list of the newly added table
1395 monikers.
1396
1397 The schema argument should be the schema class or object to be affected.  It
1398 should probably be derived from the original schema_class used during L</load>.
1399
1400 =cut
1401
1402 sub rescan {
1403     my ($self, $schema) = @_;
1404
1405     $self->{schema} = $schema;
1406     $self->_relbuilder->{schema} = $schema;
1407
1408     my @created;
1409     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
1410
1411     foreach my $table (@current) {
1412         if(!exists $self->_tables->{$table->sql_name}) {
1413             push(@created, $table);
1414         }
1415     }
1416
1417     my %current;
1418     @current{map $_->sql_name, @current} = ();
1419     foreach my $table (values %{ $self->_tables }) {
1420         if (not exists $current{$table->sql_name}) {
1421             $self->_remove_table($table);
1422         }
1423     }
1424
1425     delete @$self{qw/_dump_storage _relations_started _uniqs_started/};
1426
1427     my $loaded = $self->_load_tables(@current);
1428
1429     foreach my $table (@created) {
1430         $self->monikers->{$table->sql_name} = $self->_table2moniker($table);
1431     }
1432
1433     return map { $self->monikers->{$_->sql_name} } @created;
1434 }
1435
1436 sub _relbuilder {
1437     my ($self) = @_;
1438
1439     return if $self->{skip_relationships};
1440
1441     return $self->{relbuilder} ||= do {
1442         my $relbuilder_suff =
1443             {qw{
1444                 v4  ::Compat::v0_040
1445                 v5  ::Compat::v0_05
1446                 v6  ::Compat::v0_06
1447                 v7  ::Compat::v0_07
1448             }}
1449             ->{$self->naming->{relationships}||$CURRENT_V} || '';
1450
1451         my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1452         $self->ensure_class_loaded($relbuilder_class);
1453         $relbuilder_class->new($self);
1454     };
1455 }
1456
1457 sub _load_tables {
1458     my ($self, @tables) = @_;
1459
1460     # Save the new tables to the tables list
1461     foreach (@tables) {
1462         $self->_tables->{$_->sql_name} = $_;
1463     }
1464
1465     $self->_make_src_class($_) for @tables;
1466
1467     # sanity-check for moniker clashes
1468     my $inverse_moniker_idx;
1469     foreach my $table (values %{ $self->_tables }) {
1470       push @{ $inverse_moniker_idx->{$self->monikers->{$table->sql_name}} }, $table;
1471     }
1472
1473     my @clashes;
1474     foreach my $moniker (keys %$inverse_moniker_idx) {
1475       my $tables = $inverse_moniker_idx->{$moniker};
1476       if (@$tables > 1) {
1477         push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1478           join (', ', map $_->sql_name, @$tables),
1479           $moniker,
1480         );
1481       }
1482     }
1483
1484     if (@clashes) {
1485       die   'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1486           . 'In multi db_schema configurations you may need to set moniker_parts, '
1487           . 'otherwise change the naming style, or supply an explicit moniker_map: '
1488           . join ('; ', @clashes)
1489           . "\n"
1490       ;
1491     }
1492
1493     $self->_setup_src_meta($_) for @tables;
1494
1495     if(!$self->skip_relationships) {
1496         # The relationship loader needs a working schema
1497         local $self->{quiet} = 1;
1498         local $self->{dump_directory} = $self->{temp_directory};
1499         $self->_reload_classes(\@tables);
1500         $self->_load_relationships(\@tables);
1501
1502         # Remove that temp dir from INC so it doesn't get reloaded
1503         @INC = grep $_ ne $self->dump_directory, @INC;
1504     }
1505
1506     $self->_load_roles($_) for @tables;
1507
1508     $self->_load_external($_)
1509         for map { $self->classes->{$_->sql_name} } @tables;
1510
1511     # Reload without unloading first to preserve any symbols from external
1512     # packages.
1513     $self->_reload_classes(\@tables, { unload => 0 });
1514
1515     # Drop temporary cache
1516     delete $self->{_cache};
1517
1518     return \@tables;
1519 }
1520
1521 sub _reload_classes {
1522     my ($self, $tables, $opts) = @_;
1523
1524     my @tables = @$tables;
1525
1526     my $unload = $opts->{unload};
1527     $unload = 1 unless defined $unload;
1528
1529     # so that we don't repeat custom sections
1530     @INC = grep $_ ne $self->dump_directory, @INC;
1531
1532     $self->_dump_to_dir(map { $self->classes->{$_->sql_name} } @tables);
1533
1534     unshift @INC, $self->dump_directory;
1535     
1536     my @to_register;
1537     my %have_source = map { $_ => $self->schema->source($_) }
1538         $self->schema->sources;
1539
1540     for my $table (@tables) {
1541         my $moniker = $self->monikers->{$table->sql_name};
1542         my $class = $self->classes->{$table->sql_name};
1543         
1544         {
1545             no warnings 'redefine';
1546             local *Class::C3::reinitialize = sub {};  # to speed things up, reinitialized below
1547             use warnings;
1548
1549             if (my $mc = $self->_moose_metaclass($class)) {
1550                 $mc->make_mutable;
1551             }
1552             Class::Unload->unload($class) if $unload;
1553             my ($source, $resultset_class);
1554             if (
1555                 ($source = $have_source{$moniker})
1556                 && ($resultset_class = $source->resultset_class)
1557                 && ($resultset_class ne 'DBIx::Class::ResultSet')
1558             ) {
1559                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1560                 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1561                     $mc->make_mutable;
1562                 }
1563                 Class::Unload->unload($resultset_class) if $unload;
1564                 $self->_reload_class($resultset_class) if $has_file;
1565             }
1566             $self->_reload_class($class);
1567         }
1568         push @to_register, [$moniker, $class];
1569     }
1570
1571     Class::C3->reinitialize;
1572     for (@to_register) {
1573         $self->schema->register_class(@$_);
1574     }
1575 }
1576
1577 sub _moose_metaclass {
1578   return undef unless $INC{'Class/MOP.pm'};   # if CMOP is not loaded the class could not have loaded in the 1st place
1579
1580   my $class = $_[1];
1581
1582   my $mc = try { Class::MOP::class_of($class) }
1583     or return undef;
1584
1585   return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1586 }
1587
1588 # We use this instead of ensure_class_loaded when there are package symbols we
1589 # want to preserve.
1590 sub _reload_class {
1591     my ($self, $class) = @_;
1592
1593     delete $INC{ +class_path($class) };
1594
1595     try {
1596         eval_package_without_redefine_warnings ($class, "require $class");
1597     }
1598     catch {
1599         my $source = slurp_file $self->_get_dump_filename($class);
1600         die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
1601     };
1602 }
1603
1604 sub _get_dump_filename {
1605     my ($self, $class) = (@_);
1606
1607     $class =~ s{::}{/}g;
1608     return $self->dump_directory . q{/} . $class . q{.pm};
1609 }
1610
1611 =head2 get_dump_filename
1612
1613 Arguments: class
1614
1615 Returns the full path to the file for a class that the class has been or will
1616 be dumped to. This is a file in a temp dir for a dynamic schema.
1617
1618 =cut
1619
1620 sub get_dump_filename {
1621     my ($self, $class) = (@_);
1622
1623     local $self->{dump_directory} = $self->real_dump_directory;
1624
1625     return $self->_get_dump_filename($class);
1626 }
1627
1628 sub _ensure_dump_subdirs {
1629     my ($self, $class) = (@_);
1630
1631     my @name_parts = split(/::/, $class);
1632     pop @name_parts; # we don't care about the very last element,
1633                      # which is a filename
1634
1635     my $dir = $self->dump_directory;
1636     while (1) {
1637         if(!-d $dir) {
1638             mkdir($dir) or croak "mkdir('$dir') failed: $!";
1639         }
1640         last if !@name_parts;
1641         $dir = File::Spec->catdir($dir, shift @name_parts);
1642     }
1643 }
1644
1645 sub _dump_to_dir {
1646     my ($self, @classes) = @_;
1647
1648     my $schema_class = $self->schema_class;
1649     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1650
1651     my $target_dir = $self->dump_directory;
1652     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1653         unless $self->dynamic or $self->quiet;
1654
1655     my $schema_text =
1656           qq|use utf8;\n|
1657         . qq|package $schema_class;\n\n|
1658         . qq|# Created by DBIx::Class::Schema::Loader\n|
1659         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1660
1661     if ($self->use_moose) {
1662         $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1663     }
1664     else {
1665         $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
1666     }
1667
1668     my @schema_components = @{ $self->schema_components || [] };
1669
1670     if (@schema_components) {
1671         my $schema_components = dump @schema_components;
1672         $schema_components = "($schema_components)" if @schema_components == 1;
1673
1674         $schema_text .= "__PACKAGE__->load_components${schema_components};\n\n";
1675     }
1676
1677     if ($self->use_namespaces) {
1678         $schema_text .= qq|__PACKAGE__->load_namespaces|;
1679         my $namespace_options;
1680
1681         my @attr = qw/resultset_namespace default_resultset_class/;
1682
1683         unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1684
1685         for my $attr (@attr) {
1686             if ($self->$attr) {
1687                 my $code = dumper_squashed $self->$attr;
1688                 $namespace_options .= qq|    $attr => $code,\n|
1689             }
1690         }
1691         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1692         $schema_text .= qq|;\n|;
1693     }
1694     else {
1695         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1696     }
1697
1698     {
1699         local $self->{version_to_dump} = $self->schema_version_to_dump;
1700         $self->_write_classfile($schema_class, $schema_text, 1);
1701     }
1702
1703     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1704
1705     foreach my $src_class (@classes) {
1706         my $src_text = 
1707               qq|use utf8;\n|
1708             . qq|package $src_class;\n\n|
1709             . qq|# Created by DBIx::Class::Schema::Loader\n|
1710             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1711
1712         $src_text .= $self->_make_pod_heading($src_class);
1713
1714         $src_text .= qq|use strict;\nuse warnings;\n\n|;
1715
1716         $src_text .= $self->_base_class_pod($result_base_class)
1717             unless $result_base_class eq 'DBIx::Class::Core';
1718
1719         if ($self->use_moose) {
1720             $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1721
1722             # these options 'use base' which is compile time
1723             if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1724                 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n|;
1725             }
1726             else {
1727                 $src_text .= qq|\nextends '$result_base_class';\n|;
1728             }
1729         }
1730         else {
1731              $src_text .= qq|use base '$result_base_class';\n|;
1732         }
1733
1734         $self->_write_classfile($src_class, $src_text);
1735     }
1736
1737     # remove Result dir if downgrading from use_namespaces, and there are no
1738     # files left.
1739     if (my $result_ns = $self->_downgrading_to_load_classes
1740                         || $self->_rewriting_result_namespace) {
1741         my $result_namespace = $self->_result_namespace(
1742             $schema_class,
1743             $result_ns,
1744         );
1745
1746         (my $result_dir = $result_namespace) =~ s{::}{/}g;
1747         $result_dir = $self->dump_directory . '/' . $result_dir;
1748
1749         unless (my @files = glob "$result_dir/*") {
1750             rmdir $result_dir;
1751         }
1752     }
1753
1754     warn "Schema dump completed.\n" unless $self->dynamic or $self->quiet;
1755 }
1756
1757 sub _sig_comment {
1758     my ($self, $version, $ts) = @_;
1759     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1760          . qq| v| . $version
1761          . q| @ | . $ts 
1762          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1763 }
1764
1765 sub _write_classfile {
1766     my ($self, $class, $text, $is_schema) = @_;
1767
1768     my $filename = $self->_get_dump_filename($class);
1769     $self->_ensure_dump_subdirs($class);
1770
1771     if (-f $filename && $self->really_erase_my_files) {
1772         warn "Deleting existing file '$filename' due to "
1773             . "'really_erase_my_files' setting\n" unless $self->quiet;
1774         unlink($filename);
1775     }
1776
1777     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1778         = $self->_parse_generated_file($filename);
1779
1780     if (! $old_gen && -f $filename) {
1781         croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1782             . " it does not appear to have been generated by Loader"
1783     }
1784
1785     my $custom_content = $old_custom || '';
1786
1787     # prepend extra custom content from a *renamed* class (singularization effect)
1788     if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1789         my $old_filename = $self->_get_dump_filename($renamed_class);
1790
1791         if (-f $old_filename) {
1792             my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1793
1794             $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1795
1796             $custom_content = join ("\n", '', $extra_custom, $custom_content)
1797                 if $extra_custom;
1798
1799             unlink $old_filename;
1800         }
1801     }
1802
1803     $custom_content ||= $self->_default_custom_content($is_schema);
1804
1805     # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1806     # If there is already custom content, which does not have the Moose content, add it.
1807     if ($self->use_moose) {
1808
1809         my $non_moose_custom_content = do {
1810             local $self->{use_moose} = 0;
1811             $self->_default_custom_content;
1812         };
1813
1814         if ($custom_content eq $non_moose_custom_content) {
1815             $custom_content = $self->_default_custom_content($is_schema);
1816         }
1817         elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1818             $custom_content .= $self->_default_custom_content($is_schema);
1819         }
1820     }
1821     elsif (defined $self->use_moose && $old_gen) {
1822         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'
1823             if $old_gen =~ /use \s+ MooseX?\b/x;
1824     }
1825
1826     $custom_content = $self->_rewrite_old_classnames($custom_content);
1827
1828     $text .= qq|$_\n|
1829         for @{$self->{_dump_storage}->{$class} || []};
1830
1831     if ($self->filter_generated_code) {
1832         my $filter = $self->filter_generated_code;
1833
1834         if (ref $filter eq 'CODE') {
1835             $text = $filter->(
1836                 ($is_schema ? 'schema' : 'result'),
1837                 $class,
1838                 $text
1839             );
1840         }
1841         else {
1842             my ($out, $in) = (gensym, gensym);
1843
1844             my $pid = open2($out, $in, $filter)
1845                 or croak "Could not open pipe to $filter: $!";
1846
1847             print $in $text;
1848
1849             close $in;
1850
1851             $text = decode('UTF-8', do { local $/; <$out> });
1852
1853             $text =~ s/$CR?$LF/\n/g;
1854
1855             waitpid $pid, 0;
1856
1857             my $exit_code = $? >> 8;
1858
1859             if ($exit_code != 0) {
1860                 croak "filter '$filter' exited non-zero: $exit_code";
1861             }
1862         }
1863         if (not $text or not $text =~ /\bpackage\b/) {
1864             warn("$class skipped due to filter") if $self->debug;
1865             return;
1866         }
1867     }
1868
1869     # Check and see if the dump is in fact different
1870
1871     my $compare_to;
1872     if ($old_md5) {
1873       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1874       if (Digest::MD5::md5_base64(encode 'UTF-8', $compare_to) eq $old_md5) {
1875         return unless $self->_upgrading_from && $is_schema;
1876       }
1877     }
1878
1879     $text .= $self->_sig_comment(
1880       $self->version_to_dump,
1881       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1882     );
1883
1884     open(my $fh, '>:encoding(UTF-8)', $filename)
1885         or croak "Cannot open '$filename' for writing: $!";
1886
1887     # Write the top half and its MD5 sum
1888     print $fh $text . Digest::MD5::md5_base64(encode 'UTF-8', $text) . "\n";
1889
1890     # Write out anything loaded via external partial class file in @INC
1891     print $fh qq|$_\n|
1892         for @{$self->{_ext_storage}->{$class} || []};
1893
1894     # Write out any custom content the user has added
1895     print $fh $custom_content;
1896
1897     close($fh)
1898         or croak "Error closing '$filename': $!";
1899 }
1900
1901 sub _default_moose_custom_content {
1902     my ($self, $is_schema) = @_;
1903
1904     if (not $is_schema) {
1905         return qq|\n__PACKAGE__->meta->make_immutable;|;
1906     }
1907     
1908     return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
1909 }
1910
1911 sub _default_custom_content {
1912     my ($self, $is_schema) = @_;
1913     my $default = qq|\n\n# You can replace this text with custom|
1914          . qq| code or comments, and it will be preserved on regeneration|;
1915     if ($self->use_moose) {
1916         $default .= $self->_default_moose_custom_content($is_schema);
1917     }
1918     $default .= qq|\n1;\n|;
1919     return $default;
1920 }
1921
1922 sub _parse_generated_file {
1923     my ($self, $fn) = @_;
1924
1925     return unless -f $fn;
1926
1927     open(my $fh, '<:encoding(UTF-8)', $fn)
1928         or croak "Cannot open '$fn' for reading: $!";
1929
1930     my $mark_re =
1931         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\r?\n};
1932
1933     my ($md5, $ts, $ver, $gen);
1934     while(<$fh>) {
1935         if(/$mark_re/) {
1936             my $pre_md5 = $1;
1937             $md5 = $2;
1938
1939             # Pull out the version and timestamp from the line above
1940             ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\r?\Z/m;
1941
1942             $gen .= $pre_md5;
1943             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"
1944                 if !$self->overwrite_modifications && Digest::MD5::md5_base64(encode 'UTF-8', $gen) ne $md5;
1945
1946             last;
1947         }
1948         else {
1949             $gen .= $_;
1950         }
1951     }
1952
1953     my $custom = do { local $/; <$fh> }
1954         if $md5;
1955
1956     $custom ||= '';
1957     $custom =~ s/$CRLF|$LF/\n/g;
1958
1959     close $fh;
1960
1961     return ($gen, $md5, $ver, $ts, $custom);
1962 }
1963
1964 sub _use {
1965     my $self = shift;
1966     my $target = shift;
1967
1968     foreach (@_) {
1969         warn "$target: use $_;" if $self->debug;
1970         $self->_raw_stmt($target, "use $_;");
1971     }
1972 }
1973
1974 sub _inject {
1975     my $self = shift;
1976     my $target = shift;
1977
1978     my $blist = join(q{ }, @_);
1979
1980     return unless $blist;
1981
1982     warn "$target: use base qw/$blist/;" if $self->debug;
1983     $self->_raw_stmt($target, "use base qw/$blist/;");
1984 }
1985
1986 sub _with {
1987     my $self = shift;
1988     my $target = shift;
1989
1990     my $rlist = join(q{, }, map { qq{'$_'} } @_);
1991
1992     return unless $rlist;
1993
1994     warn "$target: with $rlist;" if $self->debug;
1995     $self->_raw_stmt($target, "\nwith $rlist;");
1996 }
1997
1998 sub _result_namespace {
1999     my ($self, $schema_class, $ns) = @_;
2000     my @result_namespace;
2001
2002     $ns = $ns->[0] if ref $ns;
2003
2004     if ($ns =~ /^\+(.*)/) {
2005         # Fully qualified namespace
2006         @result_namespace = ($1)
2007     }
2008     else {
2009         # Relative namespace
2010         @result_namespace = ($schema_class, $ns);
2011     }
2012
2013     return wantarray ? @result_namespace : join '::', @result_namespace;
2014 }
2015
2016 # Create class with applicable bases, setup monikers, etc
2017 sub _make_src_class {
2018     my ($self, $table) = @_;
2019
2020     my $schema       = $self->schema;
2021     my $schema_class = $self->schema_class;
2022
2023     my $table_moniker = $self->_table2moniker($table);
2024     my @result_namespace = ($schema_class);
2025     if ($self->use_namespaces) {
2026         my $result_namespace = $self->result_namespace || 'Result';
2027         @result_namespace = $self->_result_namespace(
2028             $schema_class,
2029             $result_namespace,
2030         );
2031     }
2032     my $table_class = join(q{::}, @result_namespace, $table_moniker);
2033
2034     if ((my $upgrading_v = $self->_upgrading_from)
2035             || $self->_rewriting) {
2036         local $self->naming->{monikers} = $upgrading_v
2037             if $upgrading_v;
2038
2039         my @result_namespace = @result_namespace;
2040         if ($self->_upgrading_from_load_classes) {
2041             @result_namespace = ($schema_class);
2042         }
2043         elsif (my $ns = $self->_downgrading_to_load_classes) {
2044             @result_namespace = $self->_result_namespace(
2045                 $schema_class,
2046                 $ns,
2047             );
2048         }
2049         elsif ($ns = $self->_rewriting_result_namespace) {
2050             @result_namespace = $self->_result_namespace(
2051                 $schema_class,
2052                 $ns,
2053             );
2054         }
2055
2056         my $old_table_moniker = do {
2057             local $self->naming->{monikers} = $upgrading_v;
2058             $self->_table2moniker($table);
2059         };
2060
2061         my $old_class = join(q{::}, @result_namespace, $old_table_moniker);
2062
2063         $self->_upgrading_classes->{$table_class} = $old_class
2064             unless $table_class eq $old_class;
2065     }
2066
2067     $self->classes->{$table->sql_name}  = $table_class;
2068     $self->monikers->{$table->sql_name} = $table_moniker;
2069     $self->moniker_to_table->{$table_moniker} = $table;
2070     $self->class_to_table->{$table_class} = $table;
2071
2072     $self->_pod_class_list($table_class, 'ADDITIONAL CLASSES USED', @{$self->additional_classes});
2073
2074     $self->_use   ($table_class, @{$self->additional_classes});
2075
2076     $self->_pod_class_list($table_class, 'LEFT BASE CLASSES', @{$self->left_base_classes});
2077
2078     $self->_inject($table_class, @{$self->left_base_classes});
2079
2080     my @components = @{ $self->components || [] };
2081
2082     push @components, @{ $self->result_components_map->{$table_moniker} }
2083         if exists $self->result_components_map->{$table_moniker};
2084
2085     my @fq_components = @components;
2086     foreach my $component (@fq_components) {
2087         if ($component !~ s/^\+//) {
2088             $component = "DBIx::Class::$component";
2089         }
2090     }
2091
2092     $self->_pod_class_list($table_class, 'COMPONENTS LOADED', @fq_components);
2093
2094     $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
2095
2096     $self->_pod_class_list($table_class, 'ADDITIONAL BASE CLASSES', @{$self->additional_base_classes});
2097
2098     $self->_inject($table_class, @{$self->additional_base_classes});
2099 }
2100
2101 sub _is_result_class_method {
2102     my ($self, $name, $table) = @_;
2103
2104     my $table_moniker = $table ? $self->monikers->{$table->sql_name} : '';
2105
2106     $self->_result_class_methods({})
2107         if not defined $self->_result_class_methods;
2108
2109     if (not exists $self->_result_class_methods->{$table_moniker}) {
2110         my (@methods, %methods);
2111         my $base       = $self->result_base_class || 'DBIx::Class::Core';
2112
2113         my @components = @{ $self->components || [] };
2114
2115         push @components, @{ $self->result_components_map->{$table_moniker} }
2116             if exists $self->result_components_map->{$table_moniker};
2117
2118         for my $c (@components) {
2119             $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
2120         }
2121
2122         my @roles = @{ $self->result_roles || [] };
2123
2124         push @roles, @{ $self->result_roles_map->{$table_moniker} }
2125             if exists $self->result_roles_map->{$table_moniker};
2126
2127         for my $class ($base, @components,
2128                        ($self->use_moose ? 'Moose::Object' : ()), @roles) {
2129             $self->ensure_class_loaded($class);
2130
2131             push @methods, @{ Class::Inspector->methods($class) || [] };
2132         }
2133
2134         push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
2135
2136         @methods{@methods} = ();
2137
2138         $self->_result_class_methods->{$table_moniker} = \%methods;
2139     }
2140     my $result_methods = $self->_result_class_methods->{$table_moniker};
2141
2142     return exists $result_methods->{$name};
2143 }
2144
2145 sub _resolve_col_accessor_collisions {
2146     my ($self, $table, $col_info) = @_;
2147
2148     while (my ($col, $info) = each %$col_info) {
2149         my $accessor = $info->{accessor} || $col;
2150
2151         next if $accessor eq 'id'; # special case (very common column)
2152
2153         if ($self->_is_result_class_method($accessor, $table)) {
2154             my $mapped = 0;
2155
2156             if (my $map = $self->col_collision_map) {
2157                 for my $re (keys %$map) {
2158                     if (my @matches = $col =~ /$re/) {
2159                         $info->{accessor} = sprintf $map->{$re}, @matches;
2160                         $mapped = 1;
2161                     }
2162                 }
2163             }
2164
2165             if (not $mapped) {
2166                 warn <<"EOF";
2167 Column '$col' in table '$table' collides with an inherited method.
2168 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
2169 EOF
2170                 $info->{accessor} = undef;
2171             }
2172         }
2173     }
2174 }
2175
2176 # use the same logic to run moniker_map, col_accessor_map
2177 sub _run_user_map {
2178     my ( $self, $map, $default_code, $ident, @extra ) = @_;
2179
2180     my $default_ident = $default_code->( $ident, @extra );
2181     my $new_ident;
2182     if( $map && ref $map eq 'HASH' ) {
2183         $new_ident = $map->{ $ident };
2184     }
2185     elsif( $map && ref $map eq 'CODE' ) {
2186         $new_ident = $map->( $ident, $default_ident, @extra );
2187     }
2188
2189     $new_ident ||= $default_ident;
2190
2191     return $new_ident;
2192 }
2193
2194 sub _default_column_accessor_name {
2195     my ( $self, $column_name ) = @_;
2196
2197     my $accessor_name = $self->_to_identifier('column_accessors', $column_name, '_');
2198
2199     $accessor_name =~ s/\W+/_/g; # only if naming < v8, otherwise to_identifier
2200                                  # takes care of it
2201
2202     if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
2203         # older naming just lc'd the col accessor and that's all.
2204         return lc $accessor_name;
2205     }
2206     elsif (($self->naming->{column_accessors}||'') eq 'preserve') {
2207         return $accessor_name;
2208     }
2209
2210     return join '_', map lc, split_name $column_name;
2211 }
2212
2213 sub _make_column_accessor_name {
2214     my ($self, $column_name, $column_context_info ) = @_;
2215
2216     my $accessor = $self->_run_user_map(
2217         $self->col_accessor_map,
2218         sub { $self->_default_column_accessor_name( shift ) },
2219         $column_name,
2220         $column_context_info,
2221        );
2222
2223     return $accessor;
2224 }
2225
2226 # Set up metadata (cols, pks, etc)
2227 sub _setup_src_meta {
2228     my ($self, $table) = @_;
2229
2230     my $schema       = $self->schema;
2231     my $schema_class = $self->schema_class;
2232
2233     my $table_class   = $self->classes->{$table->sql_name};
2234     my $table_moniker = $self->monikers->{$table->sql_name};
2235
2236     $self->_dbic_stmt($table_class, 'table', $table->dbic_name);
2237
2238     my $cols     = $self->_table_columns($table);
2239     my $col_info = $self->__columns_info_for($table);
2240
2241     ### generate all the column accessor names
2242     while (my ($col, $info) = each %$col_info) {
2243         # hashref of other info that could be used by
2244         # user-defined accessor map functions
2245         my $context = {
2246             table_class     => $table_class,
2247             table_moniker   => $table_moniker,
2248             table_name      => $table,
2249             full_table_name => $table->dbic_name,
2250             schema_class    => $schema_class,
2251             column_info     => $info,
2252         };
2253
2254         $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
2255     }
2256
2257     $self->_resolve_col_accessor_collisions($table, $col_info);
2258
2259     # prune any redundant accessor names
2260     while (my ($col, $info) = each %$col_info) {
2261         no warnings 'uninitialized';
2262         delete $info->{accessor} if $info->{accessor} eq $col;
2263     }
2264
2265     my $fks = $self->_table_fk_info($table);
2266
2267     foreach my $fkdef (@$fks) {
2268         for my $col (@{ $fkdef->{local_columns} }) {
2269             $col_info->{$col}{is_foreign_key} = 1;
2270         }
2271     }
2272
2273     my $pks = $self->_table_pk_info($table) || [];
2274
2275     my %uniq_tag; # used to eliminate duplicate uniqs
2276
2277     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
2278
2279     my $uniqs = $self->_table_uniq_info($table) || [];
2280     my @uniqs;
2281
2282     foreach my $uniq (@$uniqs) {
2283         my ($name, $cols) = @$uniq;
2284         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
2285         push @uniqs, [$name, $cols];
2286     }
2287
2288     my @non_nullable_uniqs = grep {
2289         all { $col_info->{$_}{is_nullable} == 0 } @{ $_->[1] }
2290     } @uniqs;
2291
2292     if ($self->uniq_to_primary && (not @$pks) && @non_nullable_uniqs) {
2293         my @by_colnum = sort { $b->[0] <=> $a->[0] }
2294             map [ scalar @{ $_->[1] }, $_ ], @non_nullable_uniqs;
2295
2296         if (not (@by_colnum > 1 && $by_colnum[0][0] == $by_colnum[1][0])) {
2297             my @keys = map $_->[1], @by_colnum;
2298
2299             my $pk = $keys[0];
2300
2301             # remove the uniq from list
2302             @uniqs = grep { $_->[0] ne $pk->[0] } @uniqs;
2303
2304             $pks = $pk->[1];
2305         }
2306     }
2307
2308     foreach my $pkcol (@$pks) {
2309         $col_info->{$pkcol}{is_nullable} = 0;
2310     }
2311
2312     $self->_dbic_stmt(
2313         $table_class,
2314         'add_columns',
2315         map { $_, ($col_info->{$_}||{}) } @$cols
2316     );
2317
2318     $self->_dbic_stmt($table_class, 'set_primary_key', @$pks)
2319         if @$pks;
2320
2321     # Sort unique constraints by constraint name for repeatable results (rels
2322     # are sorted as well elsewhere.)
2323     @uniqs = sort { $a->[0] cmp $b->[0] } @uniqs;
2324
2325     foreach my $uniq (@uniqs) {
2326         my ($name, $cols) = @$uniq;
2327         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
2328     }
2329 }
2330
2331 sub __columns_info_for {
2332     my ($self, $table) = @_;
2333
2334     my $result = $self->_columns_info_for($table);
2335
2336     while (my ($col, $info) = each %$result) {
2337         $info = { %$info, %{ $self->_custom_column_info  ($table, $col, $info) } };
2338         $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
2339
2340         $result->{$col} = $info;
2341     }
2342
2343     return $result;
2344 }
2345
2346 =head2 tables
2347
2348 Returns a sorted list of loaded tables, using the original database table
2349 names.
2350
2351 =cut
2352
2353 sub tables {
2354     my $self = shift;
2355
2356     return values %{$self->_tables};
2357 }
2358
2359 sub _to_identifier {
2360     my ($self, $naming_key, $name, $sep_char) = @_;
2361
2362     my ($v) = ($self->naming->{$naming_key}||$CURRENT_V) =~ /^v(\d+)\z/;
2363
2364     my $to_identifier = $self->naming->{force_ascii} ?
2365         \&String::ToIdentifier::EN::to_identifier
2366         : \&String::ToIdentifier::EN::Unicode::to_identifier;
2367
2368     return $v >= 8 ? $to_identifier->($name, $sep_char) : $name;
2369 }
2370
2371 # Make a moniker from a table
2372 sub _default_table2moniker {
2373     my ($self, $table) = @_;
2374
2375     my ($v) = ($self->naming->{monikers}||$CURRENT_V) =~ /^v(\d+)\z/;
2376
2377     my @name_parts = map $table->$_, @{ $self->moniker_parts };
2378
2379     my $name_idx = firstidx { $_ eq 'name' } @{ $self->moniker_parts };
2380
2381     my @all_parts;
2382
2383     foreach my $i (0 .. $#name_parts) {
2384         my $part = $name_parts[$i];
2385
2386         if ($i != $name_idx || $v >= 8) {
2387             $part = $self->_to_identifier->('monikers', $part, '_');
2388         }
2389
2390         if ($i == $name_idx && $v == 5) {
2391             $part = Lingua::EN::Inflect::Number::to_S($part);
2392         }
2393
2394         my @part_parts = map lc, $v > 6 ? split_name $part : split /[\W_]+/, $part;
2395
2396         if ($i == $name_idx && $v >= 6) {
2397             my $as_phrase = join ' ', @part_parts;
2398
2399             my $inflected = ($self->naming->{monikers}||'') eq 'plural' ?
2400                 Lingua::EN::Inflect::Phrase::to_PL($as_phrase)
2401                 :
2402                 ($self->naming->{monikers}||'') eq 'preserve' ?
2403                     $as_phrase
2404                     :
2405                     Lingua::EN::Inflect::Phrase::to_S($as_phrase);
2406
2407             @part_parts = split /\s+/, $inflected;
2408         }
2409
2410         push @all_parts, map ucfirst, @part_parts;
2411     }
2412
2413     return join '', @all_parts;
2414 }
2415
2416 sub _table2moniker {
2417     my ( $self, $table ) = @_;
2418
2419     $self->_run_user_map(
2420         $self->moniker_map,
2421         sub { $self->_default_table2moniker( shift ) },
2422         $table
2423        );
2424 }
2425
2426 sub _load_relationships {
2427     my ($self, $tables) = @_;
2428
2429     my @tables;
2430
2431     foreach my $table (@$tables) {
2432         my $local_moniker = $self->monikers->{$table->sql_name};
2433
2434         my $tbl_fk_info = $self->_table_fk_info($table);
2435
2436         foreach my $fkdef (@$tbl_fk_info) {
2437             $fkdef->{local_table}   = $table;
2438             $fkdef->{local_moniker} = $local_moniker;
2439             $fkdef->{remote_source} =
2440                 $self->monikers->{$fkdef->{remote_table}->sql_name};
2441         }
2442         my $tbl_uniq_info = $self->_table_uniq_info($table);
2443
2444         push @tables, [ $local_moniker, $tbl_fk_info, $tbl_uniq_info ];
2445     }
2446
2447     my $rel_stmts = $self->_relbuilder->generate_code(\@tables);
2448
2449     foreach my $src_class (sort keys %$rel_stmts) {
2450         # sort by rel name
2451         my @src_stmts = map $_->[1],
2452             sort { $a->[0] cmp $b->[0] }
2453             map [ $_->{args}[0], $_ ], @{ $rel_stmts->{$src_class} };
2454
2455         foreach my $stmt (@src_stmts) {
2456             $self->_dbic_stmt($src_class,$stmt->{method}, @{$stmt->{args}});
2457         }
2458     }
2459 }
2460
2461 sub _load_roles {
2462     my ($self, $table) = @_;
2463
2464     my $table_moniker = $self->monikers->{$table->sql_name};
2465     my $table_class   = $self->classes->{$table->sql_name};
2466
2467     my @roles = @{ $self->result_roles || [] };
2468     push @roles, @{ $self->result_roles_map->{$table_moniker} }
2469         if exists $self->result_roles_map->{$table_moniker};
2470
2471     if (@roles) {
2472         $self->_pod_class_list($table_class, 'L<Moose> ROLES APPLIED', @roles);
2473
2474         $self->_with($table_class, @roles);
2475     }
2476 }
2477
2478 # Overload these in driver class:
2479
2480 # Returns an arrayref of column names
2481 sub _table_columns { croak "ABSTRACT METHOD" }
2482
2483 # Returns arrayref of pk col names
2484 sub _table_pk_info { croak "ABSTRACT METHOD" }
2485
2486 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
2487 sub _table_uniq_info { croak "ABSTRACT METHOD" }
2488
2489 # Returns an arrayref of foreign key constraints, each
2490 #   being a hashref with 3 keys:
2491 #   local_columns (arrayref), remote_columns (arrayref), remote_table
2492 sub _table_fk_info { croak "ABSTRACT METHOD" }
2493
2494 # Returns an array of lower case table names
2495 sub _tables_list { croak "ABSTRACT METHOD" }
2496
2497 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
2498 sub _dbic_stmt {
2499     my $self   = shift;
2500     my $class  = shift;
2501     my $method = shift;
2502
2503     # generate the pod for this statement, storing it with $self->_pod
2504     $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
2505
2506     my $args = dump(@_);
2507     $args = '(' . $args . ')' if @_ < 2;
2508     my $stmt = $method . $args . q{;};
2509
2510     warn qq|$class\->$stmt\n| if $self->debug;
2511     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
2512     return;
2513 }
2514
2515 sub _make_pod_heading {
2516     my ($self, $class) = @_;
2517
2518     return '' if not $self->generate_pod;
2519
2520     my $table = $self->class_to_table->{$class};
2521     my $pod;
2522
2523     my $pcm = $self->pod_comment_mode;
2524     my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
2525     $comment = $self->__table_comment($table);
2526     $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
2527     $comment_in_name   = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
2528     $comment_in_desc   = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
2529
2530     $pod .= "=head1 NAME\n\n";
2531
2532     my $table_descr = $class;
2533     $table_descr .= " - " . $comment if $comment and $comment_in_name;
2534
2535     $pod .= "$table_descr\n\n";
2536
2537     if ($comment and $comment_in_desc) {
2538         $pod .= "=head1 DESCRIPTION\n\n${comment}\n\n";
2539     }
2540     $pod .= "=cut\n\n";
2541
2542     return $pod;
2543 }
2544
2545 # generates the accompanying pod for a DBIC class method statement,
2546 # storing it with $self->_pod
2547 sub _make_pod {
2548     my $self   = shift;
2549     my $class  = shift;
2550     my $method = shift;
2551
2552     if ($method eq 'table') {
2553         my $table = $_[0];
2554         $table = $$table if ref $table eq 'SCALAR';
2555         $self->_pod($class, "=head1 TABLE: C<$table>");
2556         $self->_pod_cut($class);
2557     }
2558     elsif ( $method eq 'add_columns' ) {
2559         $self->_pod( $class, "=head1 ACCESSORS" );
2560         my $col_counter = 0;
2561         my @cols = @_;
2562         while( my ($name,$attrs) = splice @cols,0,2 ) {
2563             $col_counter++;
2564             $self->_pod( $class, '=head2 ' . $name  );
2565             $self->_pod( $class,
2566                 join "\n", map {
2567                     my $s = $attrs->{$_};
2568                     $s = !defined $s          ? 'undef'             :
2569                         length($s) == 0       ? '(empty string)'    :
2570                         ref($s) eq 'SCALAR'   ? $$s                 :
2571                         ref($s)               ? dumper_squashed $s  :
2572                         looks_like_number($s) ? $s                  : qq{'$s'};
2573
2574                     "  $_: $s"
2575                  } sort keys %$attrs,
2576             );
2577             if (my $comment = $self->__column_comment($self->class_to_table->{$class}, $col_counter, $name)) {
2578                 $self->_pod( $class, $comment );
2579             }
2580         }
2581         $self->_pod_cut( $class );
2582     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2583         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2584         my ( $accessor, $rel_class ) = @_;
2585         $self->_pod( $class, "=head2 $accessor" );
2586         $self->_pod( $class, 'Type: ' . $method );
2587         $self->_pod( $class, "Related object: L<$rel_class>" );
2588         $self->_pod_cut( $class );
2589         $self->{_relations_started} { $class } = 1;
2590     }
2591     elsif ($method eq 'add_unique_constraint') {
2592         $self->_pod($class, '=head1 UNIQUE CONSTRAINTS')
2593             unless $self->{_uniqs_started}{$class};
2594         
2595         my ($name, $cols) = @_;
2596
2597         $self->_pod($class, "=head2 C<$name>");
2598         $self->_pod($class, '=over 4');
2599         
2600         foreach my $col (@$cols) {
2601             $self->_pod($class, "=item \* L</$col>");
2602         }
2603
2604         $self->_pod($class, '=back');
2605         $self->_pod_cut($class);
2606
2607         $self->{_uniqs_started}{$class} = 1;
2608     }
2609     elsif ($method eq 'set_primary_key') {
2610         $self->_pod($class, "=head1 PRIMARY KEY");
2611         $self->_pod($class, '=over 4');
2612         
2613         foreach my $col (@_) {
2614             $self->_pod($class, "=item \* L</$col>");
2615         }
2616
2617         $self->_pod($class, '=back');
2618         $self->_pod_cut($class);
2619     }
2620 }
2621
2622 sub _pod_class_list {
2623     my ($self, $class, $title, @classes) = @_;
2624
2625     return unless @classes && $self->generate_pod;
2626
2627     $self->_pod($class, "=head1 $title");
2628     $self->_pod($class, '=over 4');
2629
2630     foreach my $link (@classes) {
2631         $self->_pod($class, "=item * L<$link>");
2632     }
2633
2634     $self->_pod($class, '=back');
2635     $self->_pod_cut($class);
2636 }
2637
2638 sub _base_class_pod {
2639     my ($self, $base_class) = @_;
2640
2641     return '' unless $self->generate_pod;
2642
2643     return <<"EOF"
2644 =head1 BASE CLASS: L<$base_class>
2645
2646 =cut
2647
2648 EOF
2649 }
2650
2651 sub _filter_comment {
2652     my ($self, $txt) = @_;
2653
2654     $txt = '' if not defined $txt;
2655
2656     $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2657
2658     return $txt;
2659 }
2660
2661 sub __table_comment {
2662     my $self = shift;
2663
2664     if (my $code = $self->can('_table_comment')) {
2665         return $self->_filter_comment($self->$code(@_));
2666     }
2667     
2668     return '';
2669 }
2670
2671 sub __column_comment {
2672     my $self = shift;
2673
2674     if (my $code = $self->can('_column_comment')) {
2675         return $self->_filter_comment($self->$code(@_));
2676     }
2677
2678     return '';
2679 }
2680
2681 # Stores a POD documentation
2682 sub _pod {
2683     my ($self, $class, $stmt) = @_;
2684     $self->_raw_stmt( $class, "\n" . $stmt  );
2685 }
2686
2687 sub _pod_cut {
2688     my ($self, $class ) = @_;
2689     $self->_raw_stmt( $class, "\n=cut\n" );
2690 }
2691
2692 # Store a raw source line for a class (for dumping purposes)
2693 sub _raw_stmt {
2694     my ($self, $class, $stmt) = @_;
2695     push(@{$self->{_dump_storage}->{$class}}, $stmt);
2696 }
2697
2698 # Like above, but separately for the externally loaded stuff
2699 sub _ext_stmt {
2700     my ($self, $class, $stmt) = @_;
2701     push(@{$self->{_ext_storage}->{$class}}, $stmt);
2702 }
2703
2704 sub _custom_column_info {
2705     my ( $self, $table_name, $column_name, $column_info ) = @_;
2706
2707     if (my $code = $self->custom_column_info) {
2708         return $code->($table_name, $column_name, $column_info) || {};
2709     }
2710     return {};
2711 }
2712
2713 sub _datetime_column_info {
2714     my ( $self, $table_name, $column_name, $column_info ) = @_;
2715     my $result = {};
2716     my $type = $column_info->{data_type} || '';
2717     if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2718             or ($type =~ /date|timestamp/i)) {
2719         $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2720         $result->{locale}   = $self->datetime_locale   if $self->datetime_locale;
2721     }
2722     return $result;
2723 }
2724
2725 sub _lc {
2726     my ($self, $name) = @_;
2727
2728     return $self->preserve_case ? $name : lc($name);
2729 }
2730
2731 sub _uc {
2732     my ($self, $name) = @_;
2733
2734     return $self->preserve_case ? $name : uc($name);
2735 }
2736
2737 sub _remove_table {
2738     my ($self, $table) = @_;
2739
2740     try {
2741         my $schema = $self->schema;
2742         # in older DBIC it's a private method
2743         my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2744         $schema->$unregister(delete $self->monikers->{$table->sql_name});
2745         delete $self->_upgrading_classes->{delete $self->classes->{$table->sql_name}};
2746         delete $self->_tables->{$table->sql_name};
2747     };
2748 }
2749
2750 # remove the dump dir from @INC on destruction
2751 sub DESTROY {
2752     my $self = shift;
2753
2754     @INC = grep $_ ne $self->dump_directory, @INC;
2755 }
2756
2757 =head2 monikers
2758
2759 Returns a hashref of loaded table to moniker mappings.  There will
2760 be two entries for each table, the original name and the "normalized"
2761 name, in the case that the two are different (such as databases
2762 that like uppercase table names, or preserve your original mixed-case
2763 definitions, or what-have-you).
2764
2765 =head2 classes
2766
2767 Returns a hashref of table to class mappings.  In some cases it will
2768 contain multiple entries per table for the original and normalized table
2769 names, as above in L</monikers>.
2770
2771 =head1 NON-ENGLISH DATABASES
2772
2773 If you use the loader on a database with table and column names in a language
2774 other than English, you will want to turn off the English language specific
2775 heuristics.
2776
2777 To do so, use something like this in your laoder options:
2778
2779     naming           => { monikers => 'v4' },
2780     inflect_singular => sub { "$_[0]_rel" },
2781     inflect_plural   => sub { "$_[0]_rel" },
2782
2783 =head1 COLUMN ACCESSOR COLLISIONS
2784
2785 Occasionally you may have a column name that collides with a perl method, such
2786 as C<can>. In such cases, the default action is to set the C<accessor> of the
2787 column spec to C<undef>.
2788
2789 You can then name the accessor yourself by placing code such as the following
2790 below the md5:
2791
2792     __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2793
2794 Another option is to use the L</col_collision_map> option.
2795
2796 =head1 RELATIONSHIP NAME COLLISIONS
2797
2798 In very rare cases, you may get a collision between a generated relationship
2799 name and a method in your Result class, for example if you have a foreign key
2800 called C<belongs_to>.
2801
2802 This is a problem because relationship names are also relationship accessor
2803 methods in L<DBIx::Class>.
2804
2805 The default behavior is to append C<_rel> to the relationship name and print
2806 out a warning that refers to this text.
2807
2808 You can also control the renaming with the L</rel_collision_map> option.
2809
2810 =head1 SEE ALSO
2811
2812 L<DBIx::Class::Schema::Loader>
2813
2814 =head1 AUTHOR
2815
2816 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2817
2818 =head1 LICENSE
2819
2820 This library is free software; you can redistribute it and/or modify it under
2821 the same terms as Perl itself.
2822
2823 =cut
2824
2825 1;
2826 # vim:et sts=4 sw=4 tw=0: