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