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