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