fix syntax error
[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';
996be9ee 23require DBIx::Class;
24
9990e58f 25our $VERSION = '0.07000';
32f784fc 26
3d95f9ff 27__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 28 schema
29 schema_class
30
31 exclude
32 constraint
33 additional_classes
34 additional_base_classes
35 left_base_classes
36 components
37 resultset_components
59cfa251 38 skip_relationships
0ca61324 39 skip_load_external
996be9ee 40 moniker_map
b639d969 41 custom_column_info
996be9ee 42 inflect_singular
43 inflect_plural
44 debug
45 dump_directory
d65cda9e 46 dump_overwrite
28b4691d 47 really_erase_my_files
f44ecc2f 48 resultset_namespace
49 default_resultset_class
9c9c2f2b 50 schema_base_class
51 result_base_class
639a1367 52 overwrite_modifications
996be9ee 53
c8c27020 54 relationship_attrs
55
996be9ee 56 db_schema
57 _tables
58 classes
f53dcdf0 59 _upgrading_classes
996be9ee 60 monikers
106a976a 61 dynamic
a8d229ff 62 naming
42e785fa 63 datetime_timezone
64 datetime_locale
73099af4 65 config_file
71a6e88a 66 loader_class
65e705c3 67/);
68
996be9ee 69
3d95f9ff 70__PACKAGE__->mk_group_accessors('simple', qw/
01012543 71 version_to_dump
1c95b304 72 schema_version_to_dump
f53dcdf0 73 _upgrading_from
f22644d7 74 _upgrading_from_load_classes
a4b94090 75 _downgrading_to_load_classes
540a8149 76 _rewriting_result_namespace
f22644d7 77 use_namespaces
540a8149 78 result_namespace
492dce8d 79 generate_pod
43b982ea 80 pod_comment_mode
81 pod_comment_spillover_length
bc1cb85e 82 preserve_case
01012543 83/);
84
996be9ee 85=head1 NAME
86
87DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
88
89=head1 SYNOPSIS
90
91See L<DBIx::Class::Schema::Loader>
92
93=head1 DESCRIPTION
94
95This is the base class for the storage-specific C<DBIx::Class::Schema::*>
96classes, and implements the common functionality between them.
97
98=head1 CONSTRUCTOR OPTIONS
99
100These constructor options are the base options for
29ddb54c 101L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 102
59cfa251 103=head2 skip_relationships
996be9ee 104
59cfa251 105Skip setting up relationships. The default is to attempt the loading
106of relationships.
996be9ee 107
0ca61324 108=head2 skip_load_external
109
110Skip loading of other classes in @INC. The default is to merge all other classes
111with the same name found in @INC into the schema file we are creating.
112
9a95164d 113=head2 naming
114
ecf930e6 115Static schemas (ones dumped to disk) will, by default, use the new-style
9a95164d 116relationship names and singularized Results, unless you're overwriting an
ecf930e6 117existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
118which case the backward compatible RelBuilder will be activated, and the
119appropriate monikerization used.
9a95164d 120
121Specifying
122
ecf930e6 123 naming => 'current'
9a95164d 124
125will disable the backward-compatible RelBuilder and use
126the new-style relationship names along with singularized Results, even when
127overwriting a dump made with an earlier version.
128
129The option also takes a hashref:
130
ecf930e6 131 naming => { relationships => 'v6', monikers => 'v6' }
a8d229ff 132
133The keys are:
134
135=over 4
136
137=item relationships
138
139How to name relationship accessors.
140
141=item monikers
142
143How to name Result classes.
144
f3a657ef 145=item column_accessors
146
147How to name column accessors in Result classes.
148
a8d229ff 149=back
9a95164d 150
151The values can be:
152
153=over 4
154
155=item current
156
ecf930e6 157Latest style, whatever that happens to be.
158
159=item v4
160
161Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
9a95164d 162
163=item v5
164
ecf930e6 165Monikers singularized as whole words, C<might_have> relationships for FKs on
166C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
9a95164d 167
ecf930e6 168Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
169the v5 RelBuilder.
170
171=item v6
9a95164d 172
19b7d71c 173All monikers and relationships are inflected using
174L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
175from relationship names.
ecf930e6 176
177In general, there is very little difference between v5 and v6 schemas.
9a95164d 178
9990e58f 179=item v7
180
181This mode is identical to C<v6> mode, except that monikerization of CamelCase
182table names is also done correctly.
183
0c1d5b47 184CamelCase column names in case-preserving mode will also be handled correctly
185for relationship name inflection. See L</preserve_case>.
19b7d71c 186
f3a657ef 187In this mode, CamelCase L</column_accessors> are normalized based on case
188transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
189
19b7d71c 190If you don't have any CamelCase table or column names, you can upgrade without
191breaking any of your code.
9990e58f 192
9a95164d 193=back
194
195Dynamic schemas will always default to the 0.04XXX relationship names and won't
196singularize Results for backward compatibility, to activate the new RelBuilder
197and singularization put this in your C<Schema.pm> file:
198
199 __PACKAGE__->naming('current');
200
201Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
202next major version upgrade:
203
204 __PACKAGE__->naming('v5');
205
492dce8d 206=head2 generate_pod
207
208By default POD will be generated for columns and relationships, using database
7f2de014 209metadata for the text if available and supported.
210
211Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
212supported for Postgres right now.
492dce8d 213
214Set this to C<0> to turn off all POD generation.
215
43b982ea 216=head2 pod_comment_mode
217
f7976fea 218Controls where table comments appear in the generated POD. Smaller table
219comments are appended to the C<NAME> section of the documentation, and larger
220ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
221section to be generated with the comment always, only use C<NAME>, or choose
222the length threshold at which the comment is forced into the description.
43b982ea 223
34896b5e 224=over 4
225
226=item name
227
228Use C<NAME> section only.
229
230=item description
231
232Force C<DESCRIPTION> always.
233
234=item auto
235
236Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
237default.
238
239=back
43b982ea 240
241=head2 pod_comment_spillover_length
242
243When pod_comment_mode is set to C<auto>, this is the length of the comment at
244which it will be forced into a separate description section.
245
246The default is C<60>
247
c8c27020 248=head2 relationship_attrs
249
250Hashref of attributes to pass to each generated relationship, listed
251by type. Also supports relationship type 'all', containing options to
252pass to all generated relationships. Attributes set for more specific
253relationship types override those set in 'all'.
254
255For example:
256
257 relationship_attrs => {
6818ce9f 258 belongs_to => { is_deferrable => 1 },
c8c27020 259 },
260
6818ce9f 261use this to make your foreign key constraints DEFERRABLE.
c8c27020 262
996be9ee 263=head2 debug
264
265If set to true, each constructive L<DBIx::Class> statement the loader
266decides to execute will be C<warn>-ed before execution.
267
d65cda9e 268=head2 db_schema
269
270Set the name of the schema to load (schema in the sense that your database
271vendor means it). Does not currently support loading more than one schema
272name.
273
996be9ee 274=head2 constraint
275
276Only load tables matching regex. Best specified as a qr// regex.
277
278=head2 exclude
279
280Exclude tables matching regex. Best specified as a qr// regex.
281
282=head2 moniker_map
283
8f9d7ce5 284Overrides the default table name to moniker translation. Can be either
285a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 286function taking a single scalar table name argument and returning
287a scalar moniker. If the hash entry does not exist, or the function
288returns a false value, the code falls back to default behavior
289for that table name.
290
9990e58f 291The default behavior is to split on case transition and non-alphanumeric
292boundaries, singularize the resulting phrase, then join the titlecased words
293together. Examples:
996be9ee 294
9990e58f 295 Table Name | Moniker Name
296 ---------------------------------
297 luser | Luser
298 luser_group | LuserGroup
299 luser-opts | LuserOpt
300 stations_visited | StationVisited
301 routeChange | RouteChange
996be9ee 302
303=head2 inflect_plural
304
305Just like L</moniker_map> above (can be hash/code-ref, falls back to default
306if hash key does not exist or coderef returns false), but acts as a map
307for pluralizing relationship names. The default behavior is to utilize
308L<Lingua::EN::Inflect::Number/to_PL>.
309
310=head2 inflect_singular
311
312As L</inflect_plural> above, but for singularizing relationship names.
313Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
314
9c9c2f2b 315=head2 schema_base_class
316
317Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
318
319=head2 result_base_class
320
2229729e 321Base class for your table classes (aka result classes). Defaults to
322'DBIx::Class::Core'.
9c9c2f2b 323
996be9ee 324=head2 additional_base_classes
325
326List of additional base classes all of your table classes will use.
327
328=head2 left_base_classes
329
330List of additional base classes all of your table classes will use
331that need to be leftmost.
332
333=head2 additional_classes
334
335List of additional classes which all of your table classes will use.
336
337=head2 components
338
339List of additional components to be loaded into all of your table
eccc52fe 340classes. A good example would be
341L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
996be9ee 342
343=head2 resultset_components
344
8f9d7ce5 345List of additional ResultSet components to be loaded into your table
996be9ee 346classes. A good example would be C<AlwaysRS>. Component
347C<ResultSetManager> will be automatically added to the above
348C<components> list if this option is set.
349
f44ecc2f 350=head2 use_namespaces
351
f22644d7 352This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
353a C<0>.
354
f44ecc2f 355Generate result class names suitable for
356L<DBIx::Class::Schema/load_namespaces> and call that instead of
357L<DBIx::Class::Schema/load_classes>. When using this option you can also
358specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
359C<resultset_namespace>, C<default_resultset_class>), and they will be added
360to the call (and the generated result class names adjusted appropriately).
361
996be9ee 362=head2 dump_directory
363
364This option is designed to be a tool to help you transition from this
365loader to a manually-defined schema when you decide it's time to do so.
366
367The value of this option is a perl libdir pathname. Within
368that directory this module will create a baseline manual
369L<DBIx::Class::Schema> module set, based on what it creates at runtime
370in memory.
371
372The created schema class will have the same classname as the one on
373which you are setting this option (and the ResultSource classes will be
7cab3ab7 374based on this name as well).
996be9ee 375
8f9d7ce5 376Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 377is meant for one-time manual usage.
378
379See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
380recommended way to access this functionality.
381
d65cda9e 382=head2 dump_overwrite
383
28b4691d 384Deprecated. See L</really_erase_my_files> below, which does *not* mean
385the same thing as the old C<dump_overwrite> setting from previous releases.
386
387=head2 really_erase_my_files
388
7cab3ab7 389Default false. If true, Loader will unconditionally delete any existing
390files before creating the new ones from scratch when dumping a schema to disk.
391
392The default behavior is instead to only replace the top portion of the
393file, up to and including the final stanza which contains
394C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
395leaving any customizations you placed after that as they were.
396
28b4691d 397When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 398but the aforementioned final stanza is not found, or the checksum
399contained there does not match the generated contents, Loader will
400croak and not touch the file.
d65cda9e 401
28b4691d 402You should really be using version control on your schema classes (and all
403of the rest of your code for that matter). Don't blame me if a bug in this
404code wipes something out when it shouldn't have, you've been warned.
405
639a1367 406=head2 overwrite_modifications
407
408Default false. If false, when updating existing files, Loader will
409refuse to modify any Loader-generated code that has been modified
410since its last run (as determined by the checksum Loader put in its
411comment lines).
412
413If true, Loader will discard any manual modifications that have been
414made to Loader-generated code.
415
416Again, you should be using version control on your schema classes. Be
417careful with this option.
418
3a368709 419=head2 custom_column_info
420
d67d058e 421Hook for adding extra attributes to the
422L<column_info|DBIx::Class::ResultSource/column_info> for a column.
423
424Must be a coderef that returns a hashref with the extra attributes.
425
426Receives the table name, column name and column_info.
427
428For example:
429
430 custom_column_info => sub {
431 my ($table_name, $column_name, $column_info) = @_;
432
433 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
434 return { is_snoopy => 1 };
435 }
436 },
3a368709 437
d67d058e 438This attribute can also be used to set C<inflate_datetime> on a non-datetime
439column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
3a368709 440
42e785fa 441=head2 datetime_timezone
442
d67d058e 443Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
444columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 445
446=head2 datetime_locale
447
d67d058e 448Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
449columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 450
73099af4 451=head1 config_file
452
453File in Perl format, which should return a HASH reference, from which to read
454loader options.
455
bc1cb85e 456=head1 preserve_case
457
458Usually column names are lowercased, to make them easier to work with in
459L<DBIx::Class>. This option lets you turn this behavior off, if the driver
460supports it.
461
462Drivers for case sensitive databases like Sybase ASE or MSSQL with a
463case-sensitive collation will turn this option on unconditionally.
464
465Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
466setting this option.
467
996be9ee 468=head1 METHODS
469
470None of these methods are intended for direct invocation by regular
d67d058e 471users of L<DBIx::Class::Schema::Loader>. Some are proxied via
472L<DBIx::Class::Schema::Loader>.
996be9ee 473
474=cut
475
9990e58f 476my $CURRENT_V = 'v7';
8048320c 477
c5df7397 478my @CLASS_ARGS = qw(
8048320c 479 schema_base_class result_base_class additional_base_classes
480 left_base_classes additional_classes components resultset_components
481);
66afce69 482
996be9ee 483# ensure that a peice of object data is a valid arrayref, creating
484# an empty one or encapsulating whatever's there.
485sub _ensure_arrayref {
486 my $self = shift;
487
488 foreach (@_) {
489 $self->{$_} ||= [];
490 $self->{$_} = [ $self->{$_} ]
491 unless ref $self->{$_} eq 'ARRAY';
492 }
493}
494
495=head2 new
496
497Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
498by L<DBIx::Class::Schema::Loader>.
499
500=cut
501
502sub new {
503 my ( $class, %args ) = @_;
504
505 my $self = { %args };
506
507 bless $self => $class;
508
73099af4 509 if (my $config_file = $self->config_file) {
510 my $config_opts = do $config_file;
511
512 croak "Error reading config from $config_file: $@" if $@;
513
514 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
515
516 while (my ($k, $v) = each %$config_opts) {
517 $self->{$k} = $v unless exists $self->{$k};
518 }
519 }
520
996be9ee 521 $self->_ensure_arrayref(qw/additional_classes
522 additional_base_classes
523 left_base_classes
524 components
525 resultset_components
526 /);
527
8048320c 528 $self->_validate_class_args;
529
996be9ee 530 push(@{$self->{components}}, 'ResultSetManager')
531 if @{$self->{resultset_components}};
532
533 $self->{monikers} = {};
534 $self->{classes} = {};
f53dcdf0 535 $self->{_upgrading_classes} = {};
996be9ee 536
996be9ee 537 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
538 $self->{schema} ||= $self->{schema_class};
539
28b4691d 540 croak "dump_overwrite is deprecated. Please read the"
541 . " DBIx::Class::Schema::Loader::Base documentation"
542 if $self->{dump_overwrite};
543
af31090c 544 $self->{dynamic} = ! $self->{dump_directory};
79193756 545 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 546 TMPDIR => 1,
547 CLEANUP => 1,
548 );
549
79193756 550 $self->{dump_directory} ||= $self->{temp_directory};
551
01012543 552 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 553 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 554
66afce69 555 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 556 my $naming_ver = $self->naming;
a8d229ff 557 $self->{naming} = {
558 relationships => $naming_ver,
559 monikers => $naming_ver,
f3a657ef 560 column_accessors => $naming_ver,
a8d229ff 561 };
562 }
563
66afce69 564 if ($self->naming) {
565 for (values %{ $self->naming }) {
c5df7397 566 $_ = $CURRENT_V if $_ eq 'current';
66afce69 567 }
568 }
569 $self->{naming} ||= {};
570
d67d058e 571 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
572 croak 'custom_column_info must be a CODE ref';
573 }
574
7824616e 575 $self->_check_back_compat;
9c465d2c 576
f22644d7 577 $self->use_namespaces(1) unless defined $self->use_namespaces;
492dce8d 578 $self->generate_pod(1) unless defined $self->generate_pod;
43b982ea 579 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
580 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
f22644d7 581
7824616e 582 $self;
583}
af31090c 584
7824616e 585sub _check_back_compat {
586 my ($self) = @_;
e8ad6491 587
a8d229ff 588# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 589 if ($self->dynamic) {
fb3bb595 590# just in case, though no one is likely to dump a dynamic schema
1c95b304 591 $self->schema_version_to_dump('0.04006');
a8d229ff 592
66afce69 593 if (not %{ $self->naming }) {
594 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
595
596Dynamic schema detected, will run in 0.04006 mode.
597
598Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
599to disable this warning.
a0e0a56a 600
805dbe0a 601Also consider setting 'use_namespaces => 1' if/when upgrading.
602
a0e0a56a 603See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
604details.
66afce69 605EOF
606 }
f53dcdf0 607 else {
608 $self->_upgrading_from('v4');
609 }
66afce69 610
a8d229ff 611 $self->naming->{relationships} ||= 'v4';
612 $self->naming->{monikers} ||= 'v4';
613
805dbe0a 614 if ($self->use_namespaces) {
615 $self->_upgrading_from_load_classes(1);
616 }
617 else {
618 $self->use_namespaces(0);
619 }
f22644d7 620
01012543 621 return;
622 }
623
624# otherwise check if we need backcompat mode for a static schema
7824616e 625 my $filename = $self->_get_dump_filename($self->schema_class);
626 return unless -e $filename;
627
628 open(my $fh, '<', $filename)
629 or croak "Cannot open '$filename' for reading: $!";
630
540a8149 631 my $load_classes = 0;
632 my $result_namespace = '';
f22644d7 633
7824616e 634 while (<$fh>) {
f22644d7 635 if (/^__PACKAGE__->load_classes;/) {
636 $load_classes = 1;
540a8149 637 } elsif (/result_namespace => '([^']+)'/) {
638 $result_namespace = $1;
805dbe0a 639 } elsif (my ($real_ver) =
640 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
641
642 if ($load_classes && (not defined $self->use_namespaces)) {
643 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
644
a1a91c42 645'load_classes;' static schema detected, turning off 'use_namespaces'.
805dbe0a 646
647Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
648variable to disable this warning.
649
650See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
651details.
652EOF
653 $self->use_namespaces(0);
654 }
655 elsif ($load_classes && $self->use_namespaces) {
805dbe0a 656 $self->_upgrading_from_load_classes(1);
657 }
540a8149 658 elsif ((not $load_classes) && defined $self->use_namespaces
659 && (not $self->use_namespaces)) {
a4b94090 660 $self->_downgrading_to_load_classes(
661 $result_namespace || 'Result'
662 );
663 }
540a8149 664 elsif ((not defined $self->use_namespaces)
665 || $self->use_namespaces) {
666 if (not $self->result_namespace) {
667 $self->result_namespace($result_namespace || 'Result');
668 }
669 elsif ($result_namespace ne $self->result_namespace) {
670 $self->_rewriting_result_namespace(
671 $result_namespace || 'Result'
672 );
673 }
674 }
a8d229ff 675
a8d229ff 676 # XXX when we go past .0 this will need fixing
677 my ($v) = $real_ver =~ /([1-9])/;
678 $v = "v$v";
679
c5df7397 680 last if $v eq $CURRENT_V || $real_ver =~ /^0\.\d\d999/;
a0e0a56a 681
682 if (not %{ $self->naming }) {
683 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
684
685Version $real_ver static schema detected, turning on backcompat mode.
686
687Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
688to disable this warning.
689
9990e58f 690See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
691
2a8e93e9 692See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
693from version 0.04006.
a0e0a56a 694EOF
695 }
f53dcdf0 696 else {
697 $self->_upgrading_from($v);
68d49e50 698 last;
f53dcdf0 699 }
a0e0a56a 700
f3a657ef 701 $self->naming->{relationships} ||= $v;
702 $self->naming->{monikers} ||= $v;
703 $self->naming->{column_accessors} ||= $v;
a8d229ff 704
a0e0a56a 705 $self->schema_version_to_dump($real_ver);
706
7824616e 707 last;
708 }
709 }
710 close $fh;
996be9ee 711}
712
8048320c 713sub _validate_class_args {
714 my $self = shift;
715 my $args = shift;
716
c5df7397 717 foreach my $k (@CLASS_ARGS) {
8048320c 718 next unless $self->$k;
719
720 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
721 foreach my $c (@classes) {
722 # components default to being under the DBIx::Class namespace unless they
723 # are preceeded with a '+'
724 if ( $k =~ m/components$/ && $c !~ s/^\+// ) {
725 $c = 'DBIx::Class::' . $c;
726 }
727
728 # 1 == installed, 0 == not installed, undef == invalid classname
729 my $installed = Class::Inspector->installed($c);
730 if ( defined($installed) ) {
731 if ( $installed == 0 ) {
732 croak qq/$c, as specified in the loader option "$k", is not installed/;
733 }
734 } else {
735 croak qq/$c, as specified in the loader option "$k", is an invalid class name/;
736 }
737 }
738 }
739}
740
419a2eeb 741sub _find_file_in_inc {
742 my ($self, $file) = @_;
743
744 foreach my $prefix (@INC) {
af31090c 745 my $fullpath = File::Spec->catfile($prefix, $file);
746 return $fullpath if -f $fullpath
281d0f3e 747 # abs_path throws on Windows for nonexistant files
748 and eval { Cwd::abs_path($fullpath) } ne
749 (eval { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) } || '');
419a2eeb 750 }
751
752 return;
753}
754
fb3bb595 755sub _class_path {
f96ef30f 756 my ($self, $class) = @_;
757
758 my $class_path = $class;
759 $class_path =~ s{::}{/}g;
760 $class_path .= '.pm';
761
fb3bb595 762 return $class_path;
763}
764
765sub _find_class_in_inc {
766 my ($self, $class) = @_;
767
768 return $self->_find_file_in_inc($self->_class_path($class));
769}
770
a4b94090 771sub _rewriting {
772 my $self = shift;
773
774 return $self->_upgrading_from
775 || $self->_upgrading_from_load_classes
540a8149 776 || $self->_downgrading_to_load_classes
777 || $self->_rewriting_result_namespace
778 ;
a4b94090 779}
780
b24cb177 781sub _rewrite_old_classnames {
782 my ($self, $code) = @_;
783
a4b94090 784 return $code unless $self->_rewriting;
b24cb177 785
786 my %old_classes = reverse %{ $self->_upgrading_classes };
787
788 my $re = join '|', keys %old_classes;
789 $re = qr/\b($re)\b/;
790
68d49e50 791 $code =~ s/$re/$old_classes{$1} || $1/eg;
b24cb177 792
793 return $code;
794}
795
fb3bb595 796sub _load_external {
797 my ($self, $class) = @_;
798
0ca61324 799 return if $self->{skip_load_external};
800
ffc705f3 801 # so that we don't load our own classes, under any circumstances
802 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
803
fb3bb595 804 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 805
ffc705f3 806 my $old_class = $self->_upgrading_classes->{$class}
a4b94090 807 if $self->_rewriting;
ffc705f3 808
809 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
810 if $old_class && $old_class ne $class;
811
812 return unless $real_inc_path || $old_real_inc_path;
813
814 if ($real_inc_path) {
815 # If we make it to here, we loaded an external definition
816 warn qq/# Loaded external class definition for '$class'\n/
817 if $self->debug;
818
819 open(my $fh, '<', $real_inc_path)
820 or croak "Failed to open '$real_inc_path' for reading: $!";
b24cb177 821 my $code = do { local $/; <$fh> };
ffc705f3 822 close($fh)
823 or croak "Failed to close $real_inc_path: $!";
b24cb177 824 $code = $self->_rewrite_old_classnames($code);
ffc705f3 825
826 if ($self->dynamic) { # load the class too
827 # kill redefined warnings
502b65d4 828 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 829 local $SIG{__WARN__} = sub {
502b65d4 830 $warn_handler->(@_)
831 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 832 };
b24cb177 833 eval $code;
ffc705f3 834 die $@ if $@;
835 }
b24cb177 836
837 $self->_ext_stmt($class,
838 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
839 .qq|# They are now part of the custom portion of this file\n|
840 .qq|# for you to hand-edit. If you do not either delete\n|
841 .qq|# this section or remove that file from \@INC, this section\n|
842 .qq|# will be repeated redundantly when you re-create this\n|
e770e9ce 843 .qq|# file again via Loader! See skip_load_external to disable\n|
844 .qq|# this feature.\n|
b24cb177 845 );
846 chomp $code;
847 $self->_ext_stmt($class, $code);
848 $self->_ext_stmt($class,
849 qq|# End of lines loaded from '$real_inc_path' |
850 );
996be9ee 851 }
106a976a 852
ffc705f3 853 if ($old_real_inc_path) {
854 open(my $fh, '<', $old_real_inc_path)
855 or croak "Failed to open '$old_real_inc_path' for reading: $!";
856 $self->_ext_stmt($class, <<"EOF");
857
30a4c064 858# These lines were loaded from '$old_real_inc_path',
b08ea624 859# based on the Result class name that would have been created by an older
30a4c064 860# version of the Loader. For a static schema, this happens only once during
e770e9ce 861# upgrade. See skip_load_external to disable this feature.
ffc705f3 862EOF
b24cb177 863
b0d2b300 864 my $code = slurp $old_real_inc_path;
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
b97c2c1e 912Rescan the database for newly added tables. Does
a60b5b8d 913not process drops or changes. Returns a list of
914the newly added table monikers.
915
916The schema argument should be the schema class
917or object to be affected. It should probably
918be derived from the original schema_class used
919during L</load>.
b97c2c1e 920
921=cut
922
923sub rescan {
a60b5b8d 924 my ($self, $schema) = @_;
925
926 $self->{schema} = $schema;
7824616e 927 $self->_relbuilder->{schema} = $schema;
b97c2c1e 928
929 my @created;
bfb43060 930 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
0c1d5b47 931
bfb43060 932 foreach my $table (@current) {
b97c2c1e 933 if(!exists $self->{_tables}->{$table}) {
934 push(@created, $table);
935 }
936 }
937
0c1d5b47 938 my %current;
939 @current{@current} = ();
940 foreach my $table (keys %{ $self->{_tables} }) {
941 if (not exists $current{$table}) {
942 $self->_unregister_source_for_table($table);
943 }
944 }
945
c39e3507 946 my $loaded = $self->_load_tables(@created);
a60b5b8d 947
c39e3507 948 return map { $self->monikers->{$_} } @$loaded;
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
1485 return join '_', map lc, split /(?<=[[:lower:]])[\W_]*(?=[[:upper:]])|[\W_]+/, $column_name;
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);
bc1cb85e 1509 if ($self->preserve_case) {
45be2ce7 1510 for my $col (keys %$col_info) {
f3a657ef 1511 if ($col ne lc($col)) {
1512 if ((not exists $self->naming->{column_accessors}) || (($self->naming->{column_accessors} =~ /(\d+)/)[0] >= 7)) {
1513 $col_info->{$col}{accessor} = $self->_make_column_accessor_name($col);
1514 }
1515 else {
1516 $col_info->{$col}{accessor} = lc $col;
1517 }
1518 }
c9373b79 1519 }
c9486c78 1520 }
1521 else {
1522 # XXX this needs to go away
45be2ce7 1523 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1524 }
c9373b79 1525
9fdf3d5b 1526 $self->_resolve_col_accessor_collisions($col_info);
1527
45be2ce7 1528 my $fks = $self->_table_fk_info($table);
565335e6 1529
45be2ce7 1530 for my $fkdef (@$fks) {
1531 for my $col (@{ $fkdef->{local_columns} }) {
1532 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1533 }
996be9ee 1534 }
45be2ce7 1535 $self->_dbic_stmt(
1536 $table_class,
1537 'add_columns',
1538 map { $_, ($col_info->{$_}||{}) } @$cols
1539 );
996be9ee 1540
d70c335f 1541 my %uniq_tag; # used to eliminate duplicate uniqs
1542
f96ef30f 1543 my $pks = $self->_table_pk_info($table) || [];
1544 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1545 : carp("$table has no primary key");
d70c335f 1546 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1547
f96ef30f 1548 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1549 for (@$uniqs) {
1550 my ($name, $cols) = @$_;
1551 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1552 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1553 }
1554
996be9ee 1555}
1556
d67d058e 1557sub __columns_info_for {
1558 my ($self, $table) = @_;
1559
1560 my $result = $self->_columns_info_for($table);
1561
1562 while (my ($col, $info) = each %$result) {
1563 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1564 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1565
1566 $result->{$col} = $info;
1567 }
1568
1569 return $result;
1570}
1571
996be9ee 1572=head2 tables
1573
1574Returns a sorted list of loaded tables, using the original database table
1575names.
1576
1577=cut
1578
1579sub tables {
1580 my $self = shift;
1581
b97c2c1e 1582 return keys %{$self->_tables};
996be9ee 1583}
1584
1585# Make a moniker from a table
c39e403e 1586sub _default_table2moniker {
66afce69 1587 no warnings 'uninitialized';
c39e403e 1588 my ($self, $table) = @_;
1589
a8d229ff 1590 if ($self->naming->{monikers} eq 'v4') {
1591 return join '', map ucfirst, split /[\W_]+/, lc $table;
1592 }
ecf930e6 1593 elsif ($self->naming->{monikers} eq 'v5') {
1594 return join '', map ucfirst, split /[\W_]+/,
1595 Lingua::EN::Inflect::Number::to_S(lc $table);
1596 }
9990e58f 1597 elsif ($self->naming->{monikers} eq 'v6') {
1598 (my $as_phrase = lc $table) =~ s/_+/ /g;
1599 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1600
1601 return join '', map ucfirst, split /\W+/, $inflected;
1602 }
1603
1604 my @words = map lc, split /(?<=[[:lower:]])[\W_]*(?=[[:upper:]])|[\W_]+/, $table;
1605 my $as_phrase = join ' ', @words;
ecf930e6 1606
ecf930e6 1607 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
a8d229ff 1608
ecf930e6 1609 return join '', map ucfirst, split /\W+/, $inflected;
c39e403e 1610}
1611
996be9ee 1612sub _table2moniker {
1613 my ( $self, $table ) = @_;
1614
1615 my $moniker;
1616
1617 if( ref $self->moniker_map eq 'HASH' ) {
1618 $moniker = $self->moniker_map->{$table};
1619 }
1620 elsif( ref $self->moniker_map eq 'CODE' ) {
1621 $moniker = $self->moniker_map->($table);
1622 }
1623
c39e403e 1624 $moniker ||= $self->_default_table2moniker($table);
996be9ee 1625
1626 return $moniker;
1627}
1628
1629sub _load_relationships {
e8ad6491 1630 my ($self, $table) = @_;
996be9ee 1631
e8ad6491 1632 my $tbl_fk_info = $self->_table_fk_info($table);
1633 foreach my $fkdef (@$tbl_fk_info) {
1634 $fkdef->{remote_source} =
1635 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1636 }
26f1c8c9 1637 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1638
e8ad6491 1639 my $local_moniker = $self->monikers->{$table};
7824616e 1640 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1641
996be9ee 1642 foreach my $src_class (sort keys %$rel_stmts) {
1643 my $src_stmts = $rel_stmts->{$src_class};
1644 foreach my $stmt (@$src_stmts) {
1645 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1646 }
1647 }
1648}
1649
1650# Overload these in driver class:
1651
1652# Returns an arrayref of column names
1653sub _table_columns { croak "ABSTRACT METHOD" }
1654
1655# Returns arrayref of pk col names
1656sub _table_pk_info { croak "ABSTRACT METHOD" }
1657
1658# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1659sub _table_uniq_info { croak "ABSTRACT METHOD" }
1660
1661# Returns an arrayref of foreign key constraints, each
1662# being a hashref with 3 keys:
1663# local_columns (arrayref), remote_columns (arrayref), remote_table
1664sub _table_fk_info { croak "ABSTRACT METHOD" }
1665
1666# Returns an array of lower case table names
1667sub _tables_list { croak "ABSTRACT METHOD" }
1668
1669# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1670sub _dbic_stmt {
bf654ab9 1671 my $self = shift;
1672 my $class = shift;
996be9ee 1673 my $method = shift;
bf654ab9 1674
1675 # generate the pod for this statement, storing it with $self->_pod
43b982ea 1676 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
bf654ab9 1677
1678 my $args = dump(@_);
1679 $args = '(' . $args . ')' if @_ < 2;
1680 my $stmt = $method . $args . q{;};
1681
1682 warn qq|$class\->$stmt\n| if $self->debug;
1683 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1684 return;
1685}
1686
1687# generates the accompanying pod for a DBIC class method statement,
1688# storing it with $self->_pod
1689sub _make_pod {
1690 my $self = shift;
1691 my $class = shift;
1692 my $method = shift;
1693
fbcfebdd 1694 if ( $method eq 'table' ) {
1695 my ($table) = @_;
43b982ea 1696 my $pcm = $self->pod_comment_mode;
1697 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
fbcfebdd 1698 if ( $self->can('_table_comment') ) {
43b982ea 1699 $comment = $self->_table_comment($table);
1700 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1701 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1702 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
fbcfebdd 1703 }
43b982ea 1704 $self->_pod( $class, "=head1 NAME" );
1705 my $table_descr = $class;
1706 $table_descr .= " - " . $comment if $comment and $comment_in_name;
fbcfebdd 1707 $self->{_class2table}{ $class } = $table;
1708 $self->_pod( $class, $table_descr );
43b982ea 1709 if ($comment and $comment_in_desc) {
1710 $self->_pod( $class, "=head1 DESCRIPTION" );
1711 $self->_pod( $class, $comment );
1712 }
fbcfebdd 1713 $self->_pod_cut( $class );
1714 } elsif ( $method eq 'add_columns' ) {
1715 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1716 my $col_counter = 0;
1717 my @cols = @_;
1718 while( my ($name,$attrs) = splice @cols,0,2 ) {
1719 $col_counter++;
1720 $self->_pod( $class, '=head2 ' . $name );
1721 $self->_pod( $class,
1722 join "\n", map {
1723 my $s = $attrs->{$_};
fca5431b 1724 $s = !defined $s ? 'undef' :
1725 length($s) == 0 ? '(empty string)' :
f170d55b 1726 ref($s) eq 'SCALAR' ? $$s :
1727 ref($s) ? do {
1728 my $dd = Dumper;
1729 $dd->Indent(0);
1730 $dd->Values([$s]);
1731 $dd->Dump;
1732 } :
1733 looks_like_number($s) ? $s :
1734 qq{'$s'}
fca5431b 1735 ;
79a00530 1736
1737 " $_: $s"
1738 } sort keys %$attrs,
1739 );
1740
1741 if( $self->can('_column_comment')
1742 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1743 ) {
1744 $self->_pod( $class, $comment );
1745 }
fbcfebdd 1746 }
1747 $self->_pod_cut( $class );
1748 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1749 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1750 my ( $accessor, $rel_class ) = @_;
1751 $self->_pod( $class, "=head2 $accessor" );
1752 $self->_pod( $class, 'Type: ' . $method );
1753 $self->_pod( $class, "Related object: L<$rel_class>" );
1754 $self->_pod_cut( $class );
1755 $self->{_relations_started} { $class } = 1;
1756 }
996be9ee 1757}
1758
fbcfebdd 1759# Stores a POD documentation
1760sub _pod {
1761 my ($self, $class, $stmt) = @_;
1762 $self->_raw_stmt( $class, "\n" . $stmt );
1763}
1764
1765sub _pod_cut {
1766 my ($self, $class ) = @_;
1767 $self->_raw_stmt( $class, "\n=cut\n" );
1768}
1769
996be9ee 1770# Store a raw source line for a class (for dumping purposes)
1771sub _raw_stmt {
1772 my ($self, $class, $stmt) = @_;
af31090c 1773 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1774}
1775
7cab3ab7 1776# Like above, but separately for the externally loaded stuff
1777sub _ext_stmt {
1778 my ($self, $class, $stmt) = @_;
af31090c 1779 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1780}
1781
565335e6 1782sub _quote_table_name {
1783 my ($self, $table) = @_;
1784
1785 my $qt = $self->schema->storage->sql_maker->quote_char;
1786
c177d483 1787 return $table unless $qt;
1788
565335e6 1789 if (ref $qt) {
1790 return $qt->[0] . $table . $qt->[1];
1791 }
1792
1793 return $qt . $table . $qt;
1794}
1795
b639d969 1796sub _custom_column_info {
23d1f36b 1797 my ( $self, $table_name, $column_name, $column_info ) = @_;
b639d969 1798
d67d058e 1799 if (my $code = $self->custom_column_info) {
1800 return $code->($table_name, $column_name, $column_info) || {};
b639d969 1801 }
3a368709 1802 return {};
b639d969 1803}
1804
42e785fa 1805sub _datetime_column_info {
23d1f36b 1806 my ( $self, $table_name, $column_name, $column_info ) = @_;
d67d058e 1807 my $result = {};
1808 my $type = $column_info->{data_type} || '';
1809 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
1810 or ($type =~ /date|timestamp/i)) {
1811 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
1812 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
42e785fa 1813 }
d67d058e 1814 return $result;
42e785fa 1815}
1816
bc1cb85e 1817sub _lc {
1818 my ($self, $name) = @_;
1819
1820 return $self->preserve_case ? $name : lc($name);
1821}
1822
1823sub _uc {
1824 my ($self, $name) = @_;
1825
1826 return $self->preserve_case ? $name : uc($name);
1827}
1828
0c1d5b47 1829sub _unregister_source_for_table {
1830 my ($self, $table) = @_;
1831
1832 eval {
1833 local $@;
1834 my $schema = $self->schema;
1835 # in older DBIC it's a private method
1836 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
1837 $schema->$unregister($self->_table2moniker($table));
1838 delete $self->monikers->{$table};
1839 delete $self->classes->{$table};
1840 delete $self->_upgrading_classes->{$table};
1841 delete $self->{_tables}{$table};
1842 };
1843}
1844
ffc705f3 1845# remove the dump dir from @INC on destruction
1846sub DESTROY {
1847 my $self = shift;
1848
1849 @INC = grep $_ ne $self->dump_directory, @INC;
1850}
1851
996be9ee 1852=head2 monikers
1853
8f9d7ce5 1854Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1855be two entries for each table, the original name and the "normalized"
1856name, in the case that the two are different (such as databases
1857that like uppercase table names, or preserve your original mixed-case
1858definitions, or what-have-you).
1859
1860=head2 classes
1861
8f9d7ce5 1862Returns a hashref of table to class mappings. In some cases it will
996be9ee 1863contain multiple entries per table for the original and normalized table
1864names, as above in L</monikers>.
1865
1866=head1 SEE ALSO
1867
1868L<DBIx::Class::Schema::Loader>
1869
be80bba7 1870=head1 AUTHOR
1871
9cc8e7e1 1872See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1873
1874=head1 LICENSE
1875
1876This library is free software; you can redistribute it and/or modify it under
1877the same terms as Perl itself.
1878
996be9ee 1879=cut
1880
18811;
bfb43060 1882# vim:et sts=4 sw=4 tw=0: