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