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