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