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