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