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