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