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