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