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