remove MooseX::NonMoose from Schema files under use_moose=1
[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) {
49643e1d 1223 $schema_text.= qq|use Moose;\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
49643e1d 1346 $custom_content ||= $self->_default_custom_content($is_schema);
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) {
49643e1d 1358 $custom_content = $self->_default_custom_content($is_schema);
8de81918 1359 }
49643e1d 1360 elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1361 $custom_content .= $self->_default_custom_content($is_schema);
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 {
49643e1d 1407 my ($self, $is_schema) = @_;
1408
1409 if (not $is_schema) {
1410 return qq|\n__PACKAGE__->meta->make_immutable;|;
1411 }
1412
1413 return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
c9cf9b4d 1414}
1415
79193756 1416sub _default_custom_content {
49643e1d 1417 my ($self, $is_schema) = @_;
dcaf302a 1418 my $default = qq|\n\n# You can replace this text with custom|
b8e1a9d5 1419 . qq| code or comments, and it will be preserved on regeneration|;
dcaf302a 1420 if ($self->use_moose) {
49643e1d 1421 $default .= $self->_default_moose_custom_content($is_schema);
dcaf302a 1422 }
1423 $default .= qq|\n1;\n|;
1424 return $default;
79193756 1425}
1426
8de81918 1427sub _parse_generated_file {
1428 my ($self, $fn) = @_;
7cab3ab7 1429
8de81918 1430 return unless -f $fn;
79193756 1431
8de81918 1432 open(my $fh, '<', $fn)
1433 or croak "Cannot open '$fn' for reading: $!";
7cab3ab7 1434
8de81918 1435 my $mark_re =
419a2eeb 1436 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1437
8de81918 1438 my ($md5, $ts, $ver, $gen);
7cab3ab7 1439 while(<$fh>) {
8de81918 1440 if(/$mark_re/) {
1441 my $pre_md5 = $1;
79193756 1442 $md5 = $2;
79193756 1443
8de81918 1444 # Pull out the version and timestamp from the line above
1445 ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
79193756 1446
8de81918 1447 $gen .= $pre_md5;
1448 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"
1449 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
7cab3ab7 1450
8de81918 1451 last;
7cab3ab7 1452 }
1453 else {
8de81918 1454 $gen .= $_;
7cab3ab7 1455 }
996be9ee 1456 }
1457
8de81918 1458 my $custom = do { local $/; <$fh> }
1459 if $md5;
5ef3c771 1460
8de81918 1461 close ($fh);
5ef3c771 1462
8de81918 1463 return ($gen, $md5, $ver, $ts, $custom);
996be9ee 1464}
1465
1466sub _use {
1467 my $self = shift;
1468 my $target = shift;
1469
1470 foreach (@_) {
cb54990b 1471 warn "$target: use $_;" if $self->debug;
996be9ee 1472 $self->_raw_stmt($target, "use $_;");
996be9ee 1473 }
1474}
1475
1476sub _inject {
1477 my $self = shift;
1478 my $target = shift;
996be9ee 1479
af31090c 1480 my $blist = join(q{ }, @_);
6c2b21a5 1481
1482 return unless $blist;
1483
1484 warn "$target: use base qw/$blist/;" if $self->debug;
1485 $self->_raw_stmt($target, "use base qw/$blist/;");
996be9ee 1486}
1487
540a8149 1488sub _result_namespace {
1489 my ($self, $schema_class, $ns) = @_;
1490 my @result_namespace;
1491
1492 if ($ns =~ /^\+(.*)/) {
1493 # Fully qualified namespace
1494 @result_namespace = ($1)
1495 }
1496 else {
1497 # Relative namespace
1498 @result_namespace = ($schema_class, $ns);
1499 }
1500
1501 return wantarray ? @result_namespace : join '::', @result_namespace;
1502}
1503
f96ef30f 1504# Create class with applicable bases, setup monikers, etc
1505sub _make_src_class {
1506 my ($self, $table) = @_;
996be9ee 1507
a13b2803 1508 my $schema = $self->schema;
1509 my $schema_class = $self->schema_class;
996be9ee 1510
f96ef30f 1511 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1512 my @result_namespace = ($schema_class);
1513 if ($self->use_namespaces) {
1514 my $result_namespace = $self->result_namespace || 'Result';
540a8149 1515 @result_namespace = $self->_result_namespace(
1516 $schema_class,
1517 $result_namespace,
1518 );
f44ecc2f 1519 }
1520 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1521
805dbe0a 1522 if ((my $upgrading_v = $self->_upgrading_from)
a4b94090 1523 || $self->_rewriting) {
805dbe0a 1524 local $self->naming->{monikers} = $upgrading_v
1525 if $upgrading_v;
1526
1527 my @result_namespace = @result_namespace;
a4b94090 1528 if ($self->_upgrading_from_load_classes) {
1529 @result_namespace = ($schema_class);
1530 }
1531 elsif (my $ns = $self->_downgrading_to_load_classes) {
540a8149 1532 @result_namespace = $self->_result_namespace(
1533 $schema_class,
1534 $ns,
1535 );
1536 }
1537 elsif ($ns = $self->_rewriting_result_namespace) {
1538 @result_namespace = $self->_result_namespace(
1539 $schema_class,
1540 $ns,
1541 );
a4b94090 1542 }
f53dcdf0 1543
1544 my $old_class = join(q{::}, @result_namespace,
1545 $self->_table2moniker($table));
1546
68d49e50 1547 $self->_upgrading_classes->{$table_class} = $old_class
1548 unless $table_class eq $old_class;
f53dcdf0 1549 }
1550
bfb43060 1551# this was a bad idea, should be ok now without it
1552# my $table_normalized = lc $table;
1553# $self->classes->{$table_normalized} = $table_class;
1554# $self->monikers->{$table_normalized} = $table_moniker;
1555
f96ef30f 1556 $self->classes->{$table} = $table_class;
f96ef30f 1557 $self->monikers->{$table} = $table_moniker;
996be9ee 1558
f96ef30f 1559 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1560 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1561
2229729e 1562 if (my @components = @{ $self->components }) {
1563 $self->_dbic_stmt($table_class, 'load_components', @components);
1564 }
996be9ee 1565
af31090c 1566 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1567}
996be9ee 1568
9fdf3d5b 1569sub _resolve_col_accessor_collisions {
15c4393b 1570 my ($self, $table, $col_info) = @_;
9fdf3d5b 1571
1572 my $base = $self->result_base_class || 'DBIx::Class::Core';
410e3f58 1573 my @components = map "DBIx::Class::$_", @{ $self->components || [] };
9fdf3d5b 1574
15c4393b 1575 my $table_name = ref $table ? $$table : $table;
1576
9fdf3d5b 1577 my @methods;
1578
6c2b21a5 1579 for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
9fdf3d5b 1580 eval "require ${class};";
1581 die $@ if $@;
1582
1583 push @methods, @{ Class::Inspector->methods($class) || [] };
1584 }
1585
61d1cca1 1586 push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
1587
9fdf3d5b 1588 my %methods;
1589 @methods{@methods} = ();
1590
6c2b21a5 1591 # futureproof meta
1592 $methods{meta} = undef;
1593
9fdf3d5b 1594 while (my ($col, $info) = each %$col_info) {
1595 my $accessor = $info->{accessor} || $col;
1596
c9486c78 1597 next if $accessor eq 'id'; # special case (very common column)
9fdf3d5b 1598
1599 if (exists $methods{$accessor}) {
15c4393b 1600 my $mapped = 0;
1601
1602 if (my $map = $self->col_collision_map) {
1603 for my $re (keys %$map) {
1604 if (my @matches = $col =~ /$re/) {
1605 $info->{accessor} = sprintf $map->{$re}, @matches;
1606 $mapped = 1;
1607 }
1608 }
1609 }
1610
1611 if (not $mapped) {
1612 warn <<"EOF";
1613Column $col in table $table_name collides with an inherited method.
1614See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1615EOF
1616 $info->{accessor} = undef;
1617 }
9fdf3d5b 1618 }
1619 }
1620}
1621
cfc5dce3 1622# use the same logic to run moniker_map, column_accessor_map, and
1623# relationship_name_map
1624sub _run_user_map {
1625 my ( $self, $map, $default_code, $ident, @extra ) = @_;
1626
1627 my $default_ident = $default_code->( $ident, @extra );
1628 my $new_ident;
1629 if( $map && ref $map eq 'HASH' ) {
1630 $new_ident = $map->{ $ident };
1631 }
1632 elsif( $map && ref $map eq 'CODE' ) {
1633 $new_ident = $map->( $ident, $default_ident, @extra );
1634 }
1635
1636 $new_ident ||= $default_ident;
1637
1638 return $new_ident;
1639}
1640
1641sub _default_column_accessor_name {
1642 my ( $self, $column_name ) = @_;
1643
1644 my $accessor_name = $column_name;
1645 $accessor_name =~ s/\W+/_/g;
1646
61d1cca1 1647 if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
cfc5dce3 1648 # older naming just lc'd the col accessor and that's all.
1649 return lc $accessor_name;
1650 }
f3a657ef 1651
cc4f11a2 1652 return join '_', map lc, split_name $column_name;
cfc5dce3 1653
1654}
61d1cca1 1655
cfc5dce3 1656sub _make_column_accessor_name {
1657 my ($self, $column_name, $column_context_info ) = @_;
1658
1659 my $accessor = $self->_run_user_map(
1660 $self->column_accessor_map,
1661 sub { $self->_default_column_accessor_name( shift ) },
1662 $column_name,
1663 $column_context_info,
1664 );
1665
1666 return $accessor;
f3a657ef 1667}
1668
af31090c 1669# Set up metadata (cols, pks, etc)
f96ef30f 1670sub _setup_src_meta {
1671 my ($self, $table) = @_;
996be9ee 1672
f96ef30f 1673 my $schema = $self->schema;
1674 my $schema_class = $self->schema_class;
a13b2803 1675
f96ef30f 1676 my $table_class = $self->classes->{$table};
1677 my $table_moniker = $self->monikers->{$table};
996be9ee 1678
ff30991a 1679 my $table_name = $table;
1680 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1681
c177d483 1682 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1683 $table_name = \ $self->_quote_table_name($table_name);
1684 }
1685
b1d11550 1686 my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1687
1688 # be careful to not create refs Data::Dump can "optimize"
1689 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1690
1691 $self->_dbic_stmt($table_class, 'table', $full_table_name);
996be9ee 1692
cfc5dce3 1693 my $cols = $self->_table_columns($table);
45be2ce7 1694 my $col_info = $self->__columns_info_for($table);
df55c5fa 1695
cfc5dce3 1696 ### generate all the column accessor names
df55c5fa 1697 while (my ($col, $info) = each %$col_info) {
cfc5dce3 1698 # hashref of other info that could be used by
1699 # user-defined accessor map functions
1700 my $context = {
1701 table_class => $table_class,
1702 table_moniker => $table_moniker,
1703 table_name => $table_name,
1704 full_table_name => $full_table_name,
1705 schema_class => $schema_class,
1706 column_info => $info,
1707 };
df55c5fa 1708
cfc5dce3 1709 $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
45be2ce7 1710 }
c9373b79 1711
15c4393b 1712 $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
9fdf3d5b 1713
cfc5dce3 1714 # prune any redundant accessor names
1715 while (my ($col, $info) = each %$col_info) {
1716 no warnings 'uninitialized';
1717 delete $info->{accessor} if $info->{accessor} eq $col;
1718 }
1719
45be2ce7 1720 my $fks = $self->_table_fk_info($table);
565335e6 1721
10c0c4f3 1722 foreach my $fkdef (@$fks) {
45be2ce7 1723 for my $col (@{ $fkdef->{local_columns} }) {
1724 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1725 }
996be9ee 1726 }
10c0c4f3 1727
1728 my $pks = $self->_table_pk_info($table) || [];
1729
1730 foreach my $pkcol (@$pks) {
1731 $col_info->{$pkcol}{is_nullable} = 0;
1732 }
1733
45be2ce7 1734 $self->_dbic_stmt(
1735 $table_class,
1736 'add_columns',
1737 map { $_, ($col_info->{$_}||{}) } @$cols
1738 );
996be9ee 1739
d70c335f 1740 my %uniq_tag; # used to eliminate duplicate uniqs
1741
f96ef30f 1742 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1743 : carp("$table has no primary key");
d70c335f 1744 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1745
f96ef30f 1746 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1747 for (@$uniqs) {
1748 my ($name, $cols) = @$_;
1749 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1750 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1751 }
1752
996be9ee 1753}
1754
d67d058e 1755sub __columns_info_for {
1756 my ($self, $table) = @_;
1757
1758 my $result = $self->_columns_info_for($table);
1759
1760 while (my ($col, $info) = each %$result) {
1761 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1762 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1763
1764 $result->{$col} = $info;
1765 }
1766
1767 return $result;
1768}
1769
996be9ee 1770=head2 tables
1771
1772Returns a sorted list of loaded tables, using the original database table
1773names.
1774
1775=cut
1776
1777sub tables {
1778 my $self = shift;
1779
b97c2c1e 1780 return keys %{$self->_tables};
996be9ee 1781}
1782
1783# Make a moniker from a table
c39e403e 1784sub _default_table2moniker {
66afce69 1785 no warnings 'uninitialized';
c39e403e 1786 my ($self, $table) = @_;
1787
a8d229ff 1788 if ($self->naming->{monikers} eq 'v4') {
1789 return join '', map ucfirst, split /[\W_]+/, lc $table;
1790 }
ecf930e6 1791 elsif ($self->naming->{monikers} eq 'v5') {
1792 return join '', map ucfirst, split /[\W_]+/,
1793 Lingua::EN::Inflect::Number::to_S(lc $table);
1794 }
9990e58f 1795 elsif ($self->naming->{monikers} eq 'v6') {
1796 (my $as_phrase = lc $table) =~ s/_+/ /g;
1797 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1798
1799 return join '', map ucfirst, split /\W+/, $inflected;
1800 }
1801
cc4f11a2 1802 my @words = map lc, split_name $table;
9990e58f 1803 my $as_phrase = join ' ', @words;
ecf930e6 1804
ecf930e6 1805 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
a8d229ff 1806
ecf930e6 1807 return join '', map ucfirst, split /\W+/, $inflected;
c39e403e 1808}
1809
996be9ee 1810sub _table2moniker {
1811 my ( $self, $table ) = @_;
1812
cfc5dce3 1813 $self->_run_user_map(
1814 $self->moniker_map,
1815 sub { $self->_default_table2moniker( shift ) },
1816 $table
1817 );
996be9ee 1818}
1819
1820sub _load_relationships {
e8ad6491 1821 my ($self, $table) = @_;
996be9ee 1822
e8ad6491 1823 my $tbl_fk_info = $self->_table_fk_info($table);
1824 foreach my $fkdef (@$tbl_fk_info) {
1825 $fkdef->{remote_source} =
1826 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1827 }
26f1c8c9 1828 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1829
e8ad6491 1830 my $local_moniker = $self->monikers->{$table};
7824616e 1831 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1832
996be9ee 1833 foreach my $src_class (sort keys %$rel_stmts) {
1834 my $src_stmts = $rel_stmts->{$src_class};
1835 foreach my $stmt (@$src_stmts) {
1836 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1837 }
1838 }
1839}
1840
1841# Overload these in driver class:
1842
1843# Returns an arrayref of column names
1844sub _table_columns { croak "ABSTRACT METHOD" }
1845
1846# Returns arrayref of pk col names
1847sub _table_pk_info { croak "ABSTRACT METHOD" }
1848
1849# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1850sub _table_uniq_info { croak "ABSTRACT METHOD" }
1851
1852# Returns an arrayref of foreign key constraints, each
1853# being a hashref with 3 keys:
1854# local_columns (arrayref), remote_columns (arrayref), remote_table
1855sub _table_fk_info { croak "ABSTRACT METHOD" }
1856
1857# Returns an array of lower case table names
1858sub _tables_list { croak "ABSTRACT METHOD" }
1859
1860# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1861sub _dbic_stmt {
bf654ab9 1862 my $self = shift;
1863 my $class = shift;
996be9ee 1864 my $method = shift;
bf654ab9 1865
1866 # generate the pod for this statement, storing it with $self->_pod
43b982ea 1867 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
bf654ab9 1868
1869 my $args = dump(@_);
1870 $args = '(' . $args . ')' if @_ < 2;
1871 my $stmt = $method . $args . q{;};
1872
1873 warn qq|$class\->$stmt\n| if $self->debug;
1874 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1875 return;
1876}
1877
1878# generates the accompanying pod for a DBIC class method statement,
1879# storing it with $self->_pod
1880sub _make_pod {
1881 my $self = shift;
1882 my $class = shift;
1883 my $method = shift;
1884
fbcfebdd 1885 if ( $method eq 'table' ) {
1886 my ($table) = @_;
43b982ea 1887 my $pcm = $self->pod_comment_mode;
1888 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
fd97abca 1889 $comment = $self->__table_comment($table);
1890 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1891 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1892 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
43b982ea 1893 $self->_pod( $class, "=head1 NAME" );
1894 my $table_descr = $class;
1895 $table_descr .= " - " . $comment if $comment and $comment_in_name;
fbcfebdd 1896 $self->{_class2table}{ $class } = $table;
1897 $self->_pod( $class, $table_descr );
43b982ea 1898 if ($comment and $comment_in_desc) {
1899 $self->_pod( $class, "=head1 DESCRIPTION" );
1900 $self->_pod( $class, $comment );
1901 }
fbcfebdd 1902 $self->_pod_cut( $class );
1903 } elsif ( $method eq 'add_columns' ) {
1904 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1905 my $col_counter = 0;
ceb009d3 1906 my @cols = @_;
79a00530 1907 while( my ($name,$attrs) = splice @cols,0,2 ) {
ceb009d3 1908 $col_counter++;
79a00530 1909 $self->_pod( $class, '=head2 ' . $name );
ceb009d3 1910 $self->_pod( $class,
1911 join "\n", map {
1912 my $s = $attrs->{$_};
1913 $s = !defined $s ? 'undef' :
1914 length($s) == 0 ? '(empty string)' :
1915 ref($s) eq 'SCALAR' ? $$s :
1916 ref($s) ? dumper_squashed $s :
1917 looks_like_number($s) ? $s : qq{'$s'};
1918
1919 " $_: $s"
1920 } sort keys %$attrs,
1921 );
4cd5155b 1922 if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
ceb009d3 1923 $self->_pod( $class, $comment );
1924 }
fbcfebdd 1925 }
1926 $self->_pod_cut( $class );
1927 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1928 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1929 my ( $accessor, $rel_class ) = @_;
1930 $self->_pod( $class, "=head2 $accessor" );
1931 $self->_pod( $class, 'Type: ' . $method );
1932 $self->_pod( $class, "Related object: L<$rel_class>" );
1933 $self->_pod_cut( $class );
1934 $self->{_relations_started} { $class } = 1;
1935 }
996be9ee 1936}
1937
fd97abca 1938sub _filter_comment {
1939 my ($self, $txt) = @_;
1940
1941 $txt = '' if not defined $txt;
1942
1943 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
1944
1945 return $txt;
1946}
1947
1948sub __table_comment {
1949 my $self = shift;
1950
1951 if (my $code = $self->can('_table_comment')) {
1952 return $self->_filter_comment($self->$code(@_));
1953 }
1954
1955 return '';
1956}
1957
1958sub __column_comment {
1959 my $self = shift;
1960
1961 if (my $code = $self->can('_column_comment')) {
1962 return $self->_filter_comment($self->$code(@_));
1963 }
1964
1965 return '';
1966}
1967
fbcfebdd 1968# Stores a POD documentation
1969sub _pod {
1970 my ($self, $class, $stmt) = @_;
1971 $self->_raw_stmt( $class, "\n" . $stmt );
1972}
1973
1974sub _pod_cut {
1975 my ($self, $class ) = @_;
1976 $self->_raw_stmt( $class, "\n=cut\n" );
1977}
1978
996be9ee 1979# Store a raw source line for a class (for dumping purposes)
1980sub _raw_stmt {
1981 my ($self, $class, $stmt) = @_;
af31090c 1982 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1983}
1984
7cab3ab7 1985# Like above, but separately for the externally loaded stuff
1986sub _ext_stmt {
1987 my ($self, $class, $stmt) = @_;
af31090c 1988 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1989}
1990
565335e6 1991sub _quote_table_name {
1992 my ($self, $table) = @_;
1993
1994 my $qt = $self->schema->storage->sql_maker->quote_char;
1995
c177d483 1996 return $table unless $qt;
1997
565335e6 1998 if (ref $qt) {
1999 return $qt->[0] . $table . $qt->[1];
2000 }
2001
2002 return $qt . $table . $qt;
2003}
2004
b639d969 2005sub _custom_column_info {
23d1f36b 2006 my ( $self, $table_name, $column_name, $column_info ) = @_;
b639d969 2007
d67d058e 2008 if (my $code = $self->custom_column_info) {
2009 return $code->($table_name, $column_name, $column_info) || {};
b639d969 2010 }
3a368709 2011 return {};
b639d969 2012}
2013
42e785fa 2014sub _datetime_column_info {
23d1f36b 2015 my ( $self, $table_name, $column_name, $column_info ) = @_;
d67d058e 2016 my $result = {};
2017 my $type = $column_info->{data_type} || '';
2018 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2019 or ($type =~ /date|timestamp/i)) {
2020 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2021 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
42e785fa 2022 }
d67d058e 2023 return $result;
42e785fa 2024}
2025
bc1cb85e 2026sub _lc {
2027 my ($self, $name) = @_;
2028
2029 return $self->preserve_case ? $name : lc($name);
2030}
2031
2032sub _uc {
2033 my ($self, $name) = @_;
2034
2035 return $self->preserve_case ? $name : uc($name);
2036}
2037
0c1d5b47 2038sub _unregister_source_for_table {
2039 my ($self, $table) = @_;
2040
1ad8e8c3 2041 try {
0c1d5b47 2042 local $@;
2043 my $schema = $self->schema;
2044 # in older DBIC it's a private method
2045 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2046 $schema->$unregister($self->_table2moniker($table));
2047 delete $self->monikers->{$table};
2048 delete $self->classes->{$table};
2049 delete $self->_upgrading_classes->{$table};
2050 delete $self->{_tables}{$table};
2051 };
2052}
2053
ffc705f3 2054# remove the dump dir from @INC on destruction
2055sub DESTROY {
2056 my $self = shift;
2057
2058 @INC = grep $_ ne $self->dump_directory, @INC;
2059}
2060
996be9ee 2061=head2 monikers
2062
8f9d7ce5 2063Returns a hashref of loaded table to moniker mappings. There will
996be9ee 2064be two entries for each table, the original name and the "normalized"
2065name, in the case that the two are different (such as databases
2066that like uppercase table names, or preserve your original mixed-case
2067definitions, or what-have-you).
2068
2069=head2 classes
2070
8f9d7ce5 2071Returns a hashref of table to class mappings. In some cases it will
996be9ee 2072contain multiple entries per table for the original and normalized table
2073names, as above in L</monikers>.
2074
15c4393b 2075=head1 COLUMN ACCESSOR COLLISIONS
2076
2077Occasionally you may have a column name that collides with a perl method, such
2078as C<can>. In such cases, the default action is to set the C<accessor> of the
2079column spec to C<undef>.
2080
2081You can then name the accessor yourself by placing code such as the following
2082below the md5:
2083
2084 __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2085
2086Another option is to use the L</col_collision_map> option.
2087
996be9ee 2088=head1 SEE ALSO
2089
2090L<DBIx::Class::Schema::Loader>
2091
be80bba7 2092=head1 AUTHOR
2093
9cc8e7e1 2094See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 2095
2096=head1 LICENSE
2097
2098This library is free software; you can redistribute it and/or modify it under
2099the same terms as Perl itself.
2100
996be9ee 2101=cut
2102
21031;
bfb43060 2104# vim:et sts=4 sw=4 tw=0: