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