1 package DBIx::Class::Schema::Loader::Base;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
7 use Carp::Clan qw/^DBIx::Class/;
8 use DBIx::Class::Schema::Loader::RelBuilder;
9 use Data::Dump qw/ dump /;
14 use Lingua::EN::Inflect::Number qw//;
15 use Lingua::EN::Inflect::Phrase qw//;
18 use Class::Inspector ();
19 use Data::Dumper::Concise;
20 use Scalar::Util 'looks_like_number';
21 use File::Slurp 'slurp';
22 use DBIx::Class::Schema::Loader::Utils 'split_name';
26 our $VERSION = '0.08000';
28 __PACKAGE__->mk_group_ro_accessors('simple', qw/
35 additional_base_classes
50 default_resultset_class
54 overwrite_modifications
73 __PACKAGE__->mk_group_accessors('simple', qw/
75 schema_version_to_dump
77 _upgrading_from_load_classes
78 _downgrading_to_load_classes
79 _rewriting_result_namespace
84 pod_comment_spillover_length
90 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
94 See L<DBIx::Class::Schema::Loader>
98 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
99 classes, and implements the common functionality between them.
101 =head1 CONSTRUCTOR OPTIONS
103 These constructor options are the base options for
104 L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
106 =head2 skip_relationships
108 Skip setting up relationships. The default is to attempt the loading
111 =head2 skip_load_external
113 Skip loading of other classes in @INC. The default is to merge all other classes
114 with the same name found in @INC into the schema file we are creating.
118 Static schemas (ones dumped to disk) will, by default, use the new-style
119 relationship names and singularized Results, unless you're overwriting an
120 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
121 which case the backward compatible RelBuilder will be activated, and the
122 appropriate monikerization used.
128 will disable the backward-compatible RelBuilder and use
129 the new-style relationship names along with singularized Results, even when
130 overwriting a dump made with an earlier version.
132 The option also takes a hashref:
134 naming => { relationships => 'v8', monikers => 'v8' }
142 How to name relationship accessors.
146 How to name Result classes.
148 =item column_accessors
150 How to name column accessors in Result classes.
160 Latest style, whatever that happens to be.
164 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
168 Monikers singularized as whole words, C<might_have> relationships for FKs on
169 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
171 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
176 All monikers and relationships are inflected using
177 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
178 from relationship names.
180 In general, there is very little difference between v5 and v6 schemas.
184 This mode is identical to C<v6> mode, except that monikerization of CamelCase
185 table names is also done correctly.
187 CamelCase column names in case-preserving mode will also be handled correctly
188 for relationship name inflection. See L</preserve_case>.
190 In this mode, CamelCase L</column_accessors> are normalized based on case
191 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
193 If you don't have any CamelCase table or column names, you can upgrade without
194 breaking any of your code.
198 This mode tries harder to not have collisions between column accessors and
199 belongs_to relationship accessors.
203 Dynamic schemas will always default to the 0.04XXX relationship names and won't
204 singularize Results for backward compatibility, to activate the new RelBuilder
205 and singularization put this in your C<Schema.pm> file:
207 __PACKAGE__->naming('current');
209 Or if you prefer to use 0.08XXX features but insure that nothing breaks in the
210 next major version upgrade:
212 __PACKAGE__->naming('v8');
216 By default POD will be generated for columns and relationships, using database
217 metadata for the text if available and supported.
219 Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
220 supported for Postgres right now.
222 Set this to C<0> to turn off all POD generation.
224 =head2 pod_comment_mode
226 Controls where table comments appear in the generated POD. Smaller table
227 comments are appended to the C<NAME> section of the documentation, and larger
228 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
229 section to be generated with the comment always, only use C<NAME>, or choose
230 the length threshold at which the comment is forced into the description.
236 Use C<NAME> section only.
240 Force C<DESCRIPTION> always.
244 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
249 =head2 pod_comment_spillover_length
251 When pod_comment_mode is set to C<auto>, this is the length of the comment at
252 which it will be forced into a separate description section.
256 =head2 relationship_attrs
258 Hashref of attributes to pass to each generated relationship, listed
259 by type. Also supports relationship type 'all', containing options to
260 pass to all generated relationships. Attributes set for more specific
261 relationship types override those set in 'all'.
265 relationship_attrs => {
266 belongs_to => { is_deferrable => 1 },
269 use this to make your foreign key constraints DEFERRABLE.
273 If set to true, each constructive L<DBIx::Class> statement the loader
274 decides to execute will be C<warn>-ed before execution.
278 Set the name of the schema to load (schema in the sense that your database
279 vendor means it). Does not currently support loading more than one schema
284 Only load tables matching regex. Best specified as a qr// regex.
288 Exclude tables matching regex. Best specified as a qr// regex.
292 Overrides the default table name to moniker translation. Can be either
293 a hashref of table keys and moniker values, or a coderef for a translator
294 function taking a single scalar table name argument and returning
295 a scalar moniker. If the hash entry does not exist, or the function
296 returns a false value, the code falls back to default behavior
299 The default behavior is to split on case transition and non-alphanumeric
300 boundaries, singularize the resulting phrase, then join the titlecased words
303 Table Name | Moniker Name
304 ---------------------------------
306 luser_group | LuserGroup
307 luser-opts | LuserOpt
308 stations_visited | StationVisited
309 routeChange | RouteChange
311 =head2 inflect_plural
313 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
314 if hash key does not exist or coderef returns false), but acts as a map
315 for pluralizing relationship names. The default behavior is to utilize
316 L<Lingua::EN::Inflect::Number/to_PL>.
318 =head2 inflect_singular
320 As L</inflect_plural> above, but for singularizing relationship names.
321 Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
323 =head2 schema_base_class
325 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
327 =head2 result_base_class
329 Base class for your table classes (aka result classes). Defaults to
332 =head2 additional_base_classes
334 List of additional base classes all of your table classes will use.
336 =head2 left_base_classes
338 List of additional base classes all of your table classes will use
339 that need to be leftmost.
341 =head2 additional_classes
343 List of additional classes which all of your table classes will use.
347 List of additional components to be loaded into all of your table
348 classes. A good example would be
349 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
351 =head2 resultset_components
353 List of additional ResultSet components to be loaded into your table
354 classes. A good example would be C<AlwaysRS>. Component
355 C<ResultSetManager> will be automatically added to the above
356 C<components> list if this option is set.
358 =head2 use_namespaces
360 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
363 Generate result class names suitable for
364 L<DBIx::Class::Schema/load_namespaces> and call that instead of
365 L<DBIx::Class::Schema/load_classes>. When using this option you can also
366 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
367 C<resultset_namespace>, C<default_resultset_class>), and they will be added
368 to the call (and the generated result class names adjusted appropriately).
370 =head2 dump_directory
372 This option is designed to be a tool to help you transition from this
373 loader to a manually-defined schema when you decide it's time to do so.
375 The value of this option is a perl libdir pathname. Within
376 that directory this module will create a baseline manual
377 L<DBIx::Class::Schema> module set, based on what it creates at runtime
380 The created schema class will have the same classname as the one on
381 which you are setting this option (and the ResultSource classes will be
382 based on this name as well).
384 Normally you wouldn't hard-code this setting in your schema class, as it
385 is meant for one-time manual usage.
387 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
388 recommended way to access this functionality.
390 =head2 dump_overwrite
392 Deprecated. See L</really_erase_my_files> below, which does *not* mean
393 the same thing as the old C<dump_overwrite> setting from previous releases.
395 =head2 really_erase_my_files
397 Default false. If true, Loader will unconditionally delete any existing
398 files before creating the new ones from scratch when dumping a schema to disk.
400 The default behavior is instead to only replace the top portion of the
401 file, up to and including the final stanza which contains
402 C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
403 leaving any customizations you placed after that as they were.
405 When C<really_erase_my_files> is not set, if the output file already exists,
406 but the aforementioned final stanza is not found, or the checksum
407 contained there does not match the generated contents, Loader will
408 croak and not touch the file.
410 You should really be using version control on your schema classes (and all
411 of the rest of your code for that matter). Don't blame me if a bug in this
412 code wipes something out when it shouldn't have, you've been warned.
414 =head2 overwrite_modifications
416 Default false. If false, when updating existing files, Loader will
417 refuse to modify any Loader-generated code that has been modified
418 since its last run (as determined by the checksum Loader put in its
421 If true, Loader will discard any manual modifications that have been
422 made to Loader-generated code.
424 Again, you should be using version control on your schema classes. Be
425 careful with this option.
427 =head2 custom_column_info
429 Hook for adding extra attributes to the
430 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
432 Must be a coderef that returns a hashref with the extra attributes.
434 Receives the table name, column name and column_info.
438 custom_column_info => sub {
439 my ($table_name, $column_name, $column_info) = @_;
441 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
442 return { is_snoopy => 1 };
446 This attribute can also be used to set C<inflate_datetime> on a non-datetime
447 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
449 =head2 datetime_timezone
451 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
452 columns with the DATE/DATETIME/TIMESTAMP data_types.
454 =head2 datetime_locale
456 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
457 columns with the DATE/DATETIME/TIMESTAMP data_types.
461 File in Perl format, which should return a HASH reference, from which to read
466 Usually column names are lowercased, to make them easier to work with in
467 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
470 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
471 case-sensitive collation will turn this option on unconditionally.
473 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
476 =head2 qualify_objects
478 Set to true to prepend the L</db_schema> to table names for C<<
479 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
483 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
484 L<namespace::autoclean>. The default content after the md5 sum also makes the
487 It is safe to upgrade your existing Schema to this option.
491 None of these methods are intended for direct invocation by regular
492 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
493 L<DBIx::Class::Schema::Loader>.
497 my $CURRENT_V = 'v8';
500 schema_base_class result_base_class additional_base_classes
501 left_base_classes additional_classes components resultset_components
504 # ensure that a peice of object data is a valid arrayref, creating
505 # an empty one or encapsulating whatever's there.
506 sub _ensure_arrayref {
511 $self->{$_} = [ $self->{$_} ]
512 unless ref $self->{$_} eq 'ARRAY';
518 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
519 by L<DBIx::Class::Schema::Loader>.
524 my ( $class, %args ) = @_;
526 my $self = { %args };
528 bless $self => $class;
530 if (my $config_file = $self->config_file) {
531 my $config_opts = do $config_file;
533 croak "Error reading config from $config_file: $@" if $@;
535 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
537 while (my ($k, $v) = each %$config_opts) {
538 $self->{$k} = $v unless exists $self->{$k};
542 $self->_ensure_arrayref(qw/additional_classes
543 additional_base_classes
549 $self->_validate_class_args;
551 if ($self->use_moose) {
554 require MooseX::NonMoose;
555 require namespace::autoclean;
558 die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
559 "Moose, MooseX::NonMoose and namespace::autoclean";
563 push(@{$self->{components}}, 'ResultSetManager')
564 if @{$self->{resultset_components}};
566 $self->{monikers} = {};
567 $self->{classes} = {};
568 $self->{_upgrading_classes} = {};
570 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
571 $self->{schema} ||= $self->{schema_class};
573 croak "dump_overwrite is deprecated. Please read the"
574 . " DBIx::Class::Schema::Loader::Base documentation"
575 if $self->{dump_overwrite};
577 $self->{dynamic} = ! $self->{dump_directory};
578 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
583 $self->{dump_directory} ||= $self->{temp_directory};
585 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
586 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
588 if ((not ref $self->naming) && defined $self->naming) {
589 my $naming_ver = $self->naming;
591 relationships => $naming_ver,
592 monikers => $naming_ver,
593 column_accessors => $naming_ver,
598 for (values %{ $self->naming }) {
599 $_ = $CURRENT_V if $_ eq 'current';
602 $self->{naming} ||= {};
604 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
605 croak 'custom_column_info must be a CODE ref';
608 $self->_check_back_compat;
610 $self->use_namespaces(1) unless defined $self->use_namespaces;
611 $self->generate_pod(1) unless defined $self->generate_pod;
612 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
613 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
618 sub _check_back_compat {
621 # dynamic schemas will always be in 0.04006 mode, unless overridden
622 if ($self->dynamic) {
623 # just in case, though no one is likely to dump a dynamic schema
624 $self->schema_version_to_dump('0.04006');
626 if (not %{ $self->naming }) {
627 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
629 Dynamic schema detected, will run in 0.04006 mode.
631 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
632 to disable this warning.
634 Also consider setting 'use_namespaces => 1' if/when upgrading.
636 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
641 $self->_upgrading_from('v4');
644 $self->naming->{relationships} ||= 'v4';
645 $self->naming->{monikers} ||= 'v4';
647 if ($self->use_namespaces) {
648 $self->_upgrading_from_load_classes(1);
651 $self->use_namespaces(0);
657 # otherwise check if we need backcompat mode for a static schema
658 my $filename = $self->_get_dump_filename($self->schema_class);
659 return unless -e $filename;
661 open(my $fh, '<', $filename)
662 or croak "Cannot open '$filename' for reading: $!";
664 my $load_classes = 0;
665 my $result_namespace = '';
668 if (/^__PACKAGE__->load_classes;/) {
670 } elsif (/result_namespace => '([^']+)'/) {
671 $result_namespace = $1;
672 } elsif (my ($real_ver) =
673 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
675 if ($load_classes && (not defined $self->use_namespaces)) {
676 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
678 'load_classes;' static schema detected, turning off 'use_namespaces'.
680 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
681 variable to disable this warning.
683 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
686 $self->use_namespaces(0);
688 elsif ($load_classes && $self->use_namespaces) {
689 $self->_upgrading_from_load_classes(1);
691 elsif ((not $load_classes) && defined $self->use_namespaces
692 && (not $self->use_namespaces)) {
693 $self->_downgrading_to_load_classes(
694 $result_namespace || 'Result'
697 elsif ((not defined $self->use_namespaces)
698 || $self->use_namespaces) {
699 if (not $self->result_namespace) {
700 $self->result_namespace($result_namespace || 'Result');
702 elsif ($result_namespace ne $self->result_namespace) {
703 $self->_rewriting_result_namespace(
704 $result_namespace || 'Result'
709 # XXX when we go past .0 this will need fixing
710 my ($v) = $real_ver =~ /([1-9])/;
713 last if $v eq $CURRENT_V || $real_ver =~ /^0\.\d\d999/;
715 if (not %{ $self->naming }) {
716 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
718 Version $real_ver static schema detected, turning on backcompat mode.
720 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
721 to disable this warning.
723 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
725 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
726 from version 0.04006.
730 $self->_upgrading_from($v);
734 $self->naming->{relationships} ||= $v;
735 $self->naming->{monikers} ||= $v;
736 $self->naming->{column_accessors} ||= $v;
738 $self->schema_version_to_dump($real_ver);
746 sub _validate_class_args {
750 foreach my $k (@CLASS_ARGS) {
751 next unless $self->$k;
753 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
754 foreach my $c (@classes) {
755 # components default to being under the DBIx::Class namespace unless they
756 # are preceeded with a '+'
757 if ( $k =~ m/components$/ && $c !~ s/^\+// ) {
758 $c = 'DBIx::Class::' . $c;
761 # 1 == installed, 0 == not installed, undef == invalid classname
762 my $installed = Class::Inspector->installed($c);
763 if ( defined($installed) ) {
764 if ( $installed == 0 ) {
765 croak qq/$c, as specified in the loader option "$k", is not installed/;
768 croak qq/$c, as specified in the loader option "$k", is an invalid class name/;
774 sub _find_file_in_inc {
775 my ($self, $file) = @_;
777 foreach my $prefix (@INC) {
778 my $fullpath = File::Spec->catfile($prefix, $file);
779 return $fullpath if -f $fullpath
780 # abs_path throws on Windows for nonexistant files
781 and eval { Cwd::abs_path($fullpath) } ne
782 (eval { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) } || '');
789 my ($self, $class) = @_;
791 my $class_path = $class;
792 $class_path =~ s{::}{/}g;
793 $class_path .= '.pm';
798 sub _find_class_in_inc {
799 my ($self, $class) = @_;
801 return $self->_find_file_in_inc($self->_class_path($class));
807 return $self->_upgrading_from
808 || $self->_upgrading_from_load_classes
809 || $self->_downgrading_to_load_classes
810 || $self->_rewriting_result_namespace
814 sub _rewrite_old_classnames {
815 my ($self, $code) = @_;
817 return $code unless $self->_rewriting;
819 my %old_classes = reverse %{ $self->_upgrading_classes };
821 my $re = join '|', keys %old_classes;
824 $code =~ s/$re/$old_classes{$1} || $1/eg;
830 my ($self, $class) = @_;
832 return if $self->{skip_load_external};
834 # so that we don't load our own classes, under any circumstances
835 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
837 my $real_inc_path = $self->_find_class_in_inc($class);
839 my $old_class = $self->_upgrading_classes->{$class}
840 if $self->_rewriting;
842 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
843 if $old_class && $old_class ne $class;
845 return unless $real_inc_path || $old_real_inc_path;
847 if ($real_inc_path) {
848 # If we make it to here, we loaded an external definition
849 warn qq/# Loaded external class definition for '$class'\n/
852 open(my $fh, '<', $real_inc_path)
853 or croak "Failed to open '$real_inc_path' for reading: $!";
854 my $code = do { local $/; <$fh> };
856 or croak "Failed to close $real_inc_path: $!";
857 $code = $self->_rewrite_old_classnames($code);
859 if ($self->dynamic) { # load the class too
860 # kill redefined warnings
861 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
862 local $SIG{__WARN__} = sub {
864 unless $_[0] =~ /^Subroutine \S+ redefined/;
870 $self->_ext_stmt($class,
871 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
872 .qq|# They are now part of the custom portion of this file\n|
873 .qq|# for you to hand-edit. If you do not either delete\n|
874 .qq|# this section or remove that file from \@INC, this section\n|
875 .qq|# will be repeated redundantly when you re-create this\n|
876 .qq|# file again via Loader! See skip_load_external to disable\n|
877 .qq|# this feature.\n|
880 $self->_ext_stmt($class, $code);
881 $self->_ext_stmt($class,
882 qq|# End of lines loaded from '$real_inc_path' |
886 if ($old_real_inc_path) {
887 my $code = slurp $old_real_inc_path;
889 $self->_ext_stmt($class, <<"EOF");
891 # These lines were loaded from '$old_real_inc_path',
892 # based on the Result class name that would have been created by an older
893 # version of the Loader. For a static schema, this happens only once during
894 # upgrade. See skip_load_external to disable this feature.
897 $code = $self->_rewrite_old_classnames($code);
899 if ($self->dynamic) {
902 Detected external content in '$old_real_inc_path', a class name that would have
903 been used by an older version of the Loader.
905 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
906 new name of the Result.
908 # kill redefined warnings
909 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
910 local $SIG{__WARN__} = sub {
912 unless $_[0] =~ /^Subroutine \S+ redefined/;
919 $self->_ext_stmt($class, $code);
920 $self->_ext_stmt($class,
921 qq|# End of lines loaded from '$old_real_inc_path' |
928 Does the actual schema-construction work.
936 $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
944 Rescan the database for changes. Returns a list of the newly added table
947 The schema argument should be the schema class or object to be affected. It
948 should probably be derived from the original schema_class used during L</load>.
953 my ($self, $schema) = @_;
955 $self->{schema} = $schema;
956 $self->_relbuilder->{schema} = $schema;
959 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
961 foreach my $table (@current) {
962 if(!exists $self->{_tables}->{$table}) {
963 push(@created, $table);
968 @current{@current} = ();
969 foreach my $table (keys %{ $self->{_tables} }) {
970 if (not exists $current{$table}) {
971 $self->_unregister_source_for_table($table);
975 delete $self->{_dump_storage};
976 delete $self->{_relations_started};
978 my $loaded = $self->_load_tables(@current);
980 return map { $self->monikers->{$_} } @created;
984 no warnings 'uninitialized';
987 return if $self->{skip_relationships};
989 if ($self->naming->{relationships} eq 'v4') {
990 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
991 return $self->{relbuilder} ||=
992 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
994 $self->inflect_plural,
995 $self->inflect_singular,
996 $self->relationship_attrs,
999 elsif ($self->naming->{relationships} eq 'v5') {
1000 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_05;
1001 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_05->new (
1003 $self->inflect_plural,
1004 $self->inflect_singular,
1005 $self->relationship_attrs,
1008 elsif ($self->naming->{relationships} eq 'v6') {
1009 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_06;
1010 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_06->new (
1012 $self->inflect_plural,
1013 $self->inflect_singular,
1014 $self->relationship_attrs,
1017 elsif ($self->naming->{relationships} eq 'v6') {
1018 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_07;
1019 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_07->new (
1021 $self->inflect_plural,
1022 $self->inflect_singular,
1023 $self->relationship_attrs,
1027 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
1029 $self->inflect_plural,
1030 $self->inflect_singular,
1031 $self->relationship_attrs,
1036 my ($self, @tables) = @_;
1038 # Save the new tables to the tables list
1040 $self->{_tables}->{$_} = 1;
1043 $self->_make_src_class($_) for @tables;
1045 # sanity-check for moniker clashes
1046 my $inverse_moniker_idx;
1047 for (keys %{$self->monikers}) {
1048 push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1052 for (keys %$inverse_moniker_idx) {
1053 my $tables = $inverse_moniker_idx->{$_};
1055 push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1056 join (', ', map { "'$_'" } @$tables),
1063 die 'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1064 . 'Either change the naming style, or supply an explicit moniker_map: '
1065 . join ('; ', @clashes)
1071 $self->_setup_src_meta($_) for @tables;
1073 if(!$self->skip_relationships) {
1074 # The relationship loader needs a working schema
1076 local $self->{dump_directory} = $self->{temp_directory};
1077 $self->_reload_classes(\@tables);
1078 $self->_load_relationships($_) for @tables;
1081 # Remove that temp dir from INC so it doesn't get reloaded
1082 @INC = grep $_ ne $self->dump_directory, @INC;
1085 $self->_load_external($_)
1086 for map { $self->classes->{$_} } @tables;
1088 # Reload without unloading first to preserve any symbols from external
1090 $self->_reload_classes(\@tables, 0);
1092 # Drop temporary cache
1093 delete $self->{_cache};
1098 sub _reload_classes {
1099 my ($self, $tables, $unload) = @_;
1101 my @tables = @$tables;
1102 $unload = 1 unless defined $unload;
1104 # so that we don't repeat custom sections
1105 @INC = grep $_ ne $self->dump_directory, @INC;
1107 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1109 unshift @INC, $self->dump_directory;
1112 my %have_source = map { $_ => $self->schema->source($_) }
1113 $self->schema->sources;
1115 for my $table (@tables) {
1116 my $moniker = $self->monikers->{$table};
1117 my $class = $self->classes->{$table};
1120 no warnings 'redefine';
1121 local *Class::C3::reinitialize = sub {};
1124 if ($class->can('meta') && (ref $class->meta)->isa('Moose::Meta::Class')) {
1125 $class->meta->make_mutable;
1127 Class::Unload->unload($class) if $unload;
1128 my ($source, $resultset_class);
1130 ($source = $have_source{$moniker})
1131 && ($resultset_class = $source->resultset_class)
1132 && ($resultset_class ne 'DBIx::Class::ResultSet')
1134 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1135 if ($resultset_class->can('meta') && (ref $resultset_class->meta)->isa('Moose::Meta::Class')) {
1136 $resultset_class->meta->make_mutable;
1138 Class::Unload->unload($resultset_class) if $unload;
1139 $self->_reload_class($resultset_class) if $has_file;
1141 $self->_reload_class($class);
1143 push @to_register, [$moniker, $class];
1146 Class::C3->reinitialize;
1147 for (@to_register) {
1148 $self->schema->register_class(@$_);
1152 # We use this instead of ensure_class_loaded when there are package symbols we
1155 my ($self, $class) = @_;
1157 my $class_path = $self->_class_path($class);
1158 delete $INC{ $class_path };
1160 # kill redefined warnings
1161 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
1162 local $SIG{__WARN__} = sub {
1164 unless $_[0] =~ /^Subroutine \S+ redefined/;
1166 eval "require $class;";
1167 die "Failed to reload class $class: $@" if $@;
1170 sub _get_dump_filename {
1171 my ($self, $class) = (@_);
1173 $class =~ s{::}{/}g;
1174 return $self->dump_directory . q{/} . $class . q{.pm};
1177 sub _ensure_dump_subdirs {
1178 my ($self, $class) = (@_);
1180 my @name_parts = split(/::/, $class);
1181 pop @name_parts; # we don't care about the very last element,
1182 # which is a filename
1184 my $dir = $self->dump_directory;
1187 mkdir($dir) or croak "mkdir('$dir') failed: $!";
1189 last if !@name_parts;
1190 $dir = File::Spec->catdir($dir, shift @name_parts);
1195 my ($self, @classes) = @_;
1197 my $schema_class = $self->schema_class;
1198 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1200 my $target_dir = $self->dump_directory;
1201 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1202 unless $self->{dynamic} or $self->{quiet};
1205 qq|package $schema_class;\n\n|
1206 . qq|# Created by DBIx::Class::Schema::Loader\n|
1207 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1208 . qq|use strict;\nuse warnings;\n\n|;
1209 if ($self->use_moose) {
1210 $schema_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1213 $schema_text .= qq|use base '$schema_base_class';\n\n|;
1216 if ($self->use_namespaces) {
1217 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1218 my $namespace_options;
1220 my @attr = qw/resultset_namespace default_resultset_class/;
1222 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1224 for my $attr (@attr) {
1226 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
1229 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1230 $schema_text .= qq|;\n|;
1233 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1237 local $self->{version_to_dump} = $self->schema_version_to_dump;
1238 $self->_write_classfile($schema_class, $schema_text, 1);
1241 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1243 foreach my $src_class (@classes) {
1245 qq|package $src_class;\n\n|
1246 . qq|# Created by DBIx::Class::Schema::Loader\n|
1247 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1248 . qq|use strict;\nuse warnings;\n\n|;
1249 if ($self->use_moose) {
1250 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1252 # these options 'use base' which is compile time
1253 if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1254 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1257 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1261 $src_text .= qq|use base '$result_base_class';\n\n|;
1263 $self->_write_classfile($src_class, $src_text);
1266 # remove Result dir if downgrading from use_namespaces, and there are no
1268 if (my $result_ns = $self->_downgrading_to_load_classes
1269 || $self->_rewriting_result_namespace) {
1270 my $result_namespace = $self->_result_namespace(
1275 (my $result_dir = $result_namespace) =~ s{::}{/}g;
1276 $result_dir = $self->dump_directory . '/' . $result_dir;
1278 unless (my @files = glob "$result_dir/*") {
1283 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1288 my ($self, $version, $ts) = @_;
1289 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1292 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1295 sub _write_classfile {
1296 my ($self, $class, $text, $is_schema) = @_;
1298 my $filename = $self->_get_dump_filename($class);
1299 $self->_ensure_dump_subdirs($class);
1301 if (-f $filename && $self->really_erase_my_files) {
1302 warn "Deleting existing file '$filename' due to "
1303 . "'really_erase_my_files' setting\n" unless $self->{quiet};
1307 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
1309 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1310 # If there is already custom content, which does not have the Moose content, add it.
1311 if ($self->use_moose) {
1312 local $self->{use_moose} = 0;
1314 if ($custom_content eq $self->_default_custom_content) {
1315 local $self->{use_moose} = 1;
1317 $custom_content = $self->_default_custom_content;
1320 local $self->{use_moose} = 1;
1322 if ($custom_content !~ /\Q@{[$self->_default_moose_custom_content]}\E/) {
1323 $custom_content .= $self->_default_custom_content;
1328 if (my $old_class = $self->_upgrading_classes->{$class}) {
1329 my $old_filename = $self->_get_dump_filename($old_class);
1331 my ($old_custom_content) = $self->_get_custom_content(
1332 $old_class, $old_filename, 0 # do not add default comment
1335 $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
1337 if ($old_custom_content) {
1339 "\n" . $old_custom_content . "\n" . $custom_content;
1342 unlink $old_filename;
1345 $custom_content = $self->_rewrite_old_classnames($custom_content);
1348 for @{$self->{_dump_storage}->{$class} || []};
1350 # Check and see if the dump is infact differnt
1354 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1357 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
1358 return unless $self->_upgrading_from && $is_schema;
1362 $text .= $self->_sig_comment(
1363 $self->version_to_dump,
1364 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1367 open(my $fh, '>', $filename)
1368 or croak "Cannot open '$filename' for writing: $!";
1370 # Write the top half and its MD5 sum
1371 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1373 # Write out anything loaded via external partial class file in @INC
1375 for @{$self->{_ext_storage}->{$class} || []};
1377 # Write out any custom content the user has added
1378 print $fh $custom_content;
1381 or croak "Error closing '$filename': $!";
1384 sub _default_moose_custom_content {
1385 return qq|\n__PACKAGE__->meta->make_immutable;|;
1388 sub _default_custom_content {
1390 my $default = qq|\n\n# You can replace this text with custom|
1391 . qq| content, and it will be preserved on regeneration|;
1392 if ($self->use_moose) {
1393 $default .= $self->_default_moose_custom_content;
1395 $default .= qq|\n1;\n|;
1399 sub _get_custom_content {
1400 my ($self, $class, $filename, $add_default) = @_;
1402 $add_default = 1 unless defined $add_default;
1404 return ($self->_default_custom_content) if ! -f $filename;
1406 open(my $fh, '<', $filename)
1407 or croak "Cannot open '$filename' for reading: $!";
1410 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1413 my ($md5, $ts, $ver);
1415 if(!$md5 && /$mark_re/) {
1419 # Pull out the previous version and timestamp
1420 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
1423 croak "Checksum mismatch in '$filename', the auto-generated part of the file has been modified outside of this loader. Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1424 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
1433 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
1434 . " it does not appear to have been generated by Loader"
1437 # Default custom content:
1438 $buffer ||= $self->_default_custom_content if $add_default;
1440 return ($buffer, $md5, $ver, $ts);
1448 warn "$target: use $_;" if $self->debug;
1449 $self->_raw_stmt($target, "use $_;");
1457 my $blist = join(q{ }, @_);
1459 return unless $blist;
1461 warn "$target: use base qw/$blist/;" if $self->debug;
1462 $self->_raw_stmt($target, "use base qw/$blist/;");
1465 sub _result_namespace {
1466 my ($self, $schema_class, $ns) = @_;
1467 my @result_namespace;
1469 if ($ns =~ /^\+(.*)/) {
1470 # Fully qualified namespace
1471 @result_namespace = ($1)
1474 # Relative namespace
1475 @result_namespace = ($schema_class, $ns);
1478 return wantarray ? @result_namespace : join '::', @result_namespace;
1481 # Create class with applicable bases, setup monikers, etc
1482 sub _make_src_class {
1483 my ($self, $table) = @_;
1485 my $schema = $self->schema;
1486 my $schema_class = $self->schema_class;
1488 my $table_moniker = $self->_table2moniker($table);
1489 my @result_namespace = ($schema_class);
1490 if ($self->use_namespaces) {
1491 my $result_namespace = $self->result_namespace || 'Result';
1492 @result_namespace = $self->_result_namespace(
1497 my $table_class = join(q{::}, @result_namespace, $table_moniker);
1499 if ((my $upgrading_v = $self->_upgrading_from)
1500 || $self->_rewriting) {
1501 local $self->naming->{monikers} = $upgrading_v
1504 my @result_namespace = @result_namespace;
1505 if ($self->_upgrading_from_load_classes) {
1506 @result_namespace = ($schema_class);
1508 elsif (my $ns = $self->_downgrading_to_load_classes) {
1509 @result_namespace = $self->_result_namespace(
1514 elsif ($ns = $self->_rewriting_result_namespace) {
1515 @result_namespace = $self->_result_namespace(
1521 my $old_class = join(q{::}, @result_namespace,
1522 $self->_table2moniker($table));
1524 $self->_upgrading_classes->{$table_class} = $old_class
1525 unless $table_class eq $old_class;
1528 # this was a bad idea, should be ok now without it
1529 # my $table_normalized = lc $table;
1530 # $self->classes->{$table_normalized} = $table_class;
1531 # $self->monikers->{$table_normalized} = $table_moniker;
1533 $self->classes->{$table} = $table_class;
1534 $self->monikers->{$table} = $table_moniker;
1536 $self->_use ($table_class, @{$self->additional_classes});
1537 $self->_inject($table_class, @{$self->left_base_classes});
1539 if (my @components = @{ $self->components }) {
1540 $self->_dbic_stmt($table_class, 'load_components', @components);
1543 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1544 if @{$self->resultset_components};
1545 $self->_inject($table_class, @{$self->additional_base_classes});
1548 sub _resolve_col_accessor_collisions {
1549 my ($self, $col_info) = @_;
1551 my $base = $self->result_base_class || 'DBIx::Class::Core';
1552 my @components = map "DBIx::Class::$_", @{ $self->components || [] };
1556 for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
1557 eval "require ${class};";
1560 push @methods, @{ Class::Inspector->methods($class) || [] };
1564 @methods{@methods} = ();
1567 $methods{meta} = undef;
1569 while (my ($col, $info) = each %$col_info) {
1570 my $accessor = $info->{accessor} || $col;
1572 next if $accessor eq 'id'; # special case (very common column)
1574 if (exists $methods{$accessor}) {
1575 $info->{accessor} = undef;
1580 sub _make_column_accessor_name {
1581 my ($self, $column_name) = @_;
1583 return join '_', map lc, split_name $column_name;
1586 # Set up metadata (cols, pks, etc)
1587 sub _setup_src_meta {
1588 my ($self, $table) = @_;
1590 my $schema = $self->schema;
1591 my $schema_class = $self->schema_class;
1593 my $table_class = $self->classes->{$table};
1594 my $table_moniker = $self->monikers->{$table};
1596 my $table_name = $table;
1597 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1599 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1600 $table_name = \ $self->_quote_table_name($table_name);
1603 my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1605 # be careful to not create refs Data::Dump can "optimize"
1606 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1608 $self->_dbic_stmt($table_class, 'table', $full_table_name);
1610 my $cols = $self->_table_columns($table);
1611 my $col_info = $self->__columns_info_for($table);
1613 while (my ($col, $info) = each %$col_info) {
1615 ($info->{accessor} = $col) =~ s/\W+/_/g;
1619 if ($self->preserve_case) {
1620 while (my ($col, $info) = each %$col_info) {
1621 if ($col ne lc($col)) {
1622 if ((not exists $self->naming->{column_accessors}) || (($self->naming->{column_accessors} =~ /(\d+)/)[0] >= 7)) {
1623 $info->{accessor} = $self->_make_column_accessor_name($info->{accessor} || $col);
1626 $info->{accessor} = lc($info->{accessor} || $col);
1632 # XXX this needs to go away
1633 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1636 $self->_resolve_col_accessor_collisions($col_info);
1638 my $fks = $self->_table_fk_info($table);
1640 foreach my $fkdef (@$fks) {
1641 for my $col (@{ $fkdef->{local_columns} }) {
1642 $col_info->{$col}{is_foreign_key} = 1;
1646 my $pks = $self->_table_pk_info($table) || [];
1648 foreach my $pkcol (@$pks) {
1649 $col_info->{$pkcol}{is_nullable} = 0;
1655 map { $_, ($col_info->{$_}||{}) } @$cols
1658 my %uniq_tag; # used to eliminate duplicate uniqs
1660 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1661 : carp("$table has no primary key");
1662 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1664 my $uniqs = $self->_table_uniq_info($table) || [];
1666 my ($name, $cols) = @$_;
1667 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1668 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1673 sub __columns_info_for {
1674 my ($self, $table) = @_;
1676 my $result = $self->_columns_info_for($table);
1678 while (my ($col, $info) = each %$result) {
1679 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1680 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1682 $result->{$col} = $info;
1690 Returns a sorted list of loaded tables, using the original database table
1698 return keys %{$self->_tables};
1701 # Make a moniker from a table
1702 sub _default_table2moniker {
1703 no warnings 'uninitialized';
1704 my ($self, $table) = @_;
1706 if ($self->naming->{monikers} eq 'v4') {
1707 return join '', map ucfirst, split /[\W_]+/, lc $table;
1709 elsif ($self->naming->{monikers} eq 'v5') {
1710 return join '', map ucfirst, split /[\W_]+/,
1711 Lingua::EN::Inflect::Number::to_S(lc $table);
1713 elsif ($self->naming->{monikers} eq 'v6') {
1714 (my $as_phrase = lc $table) =~ s/_+/ /g;
1715 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1717 return join '', map ucfirst, split /\W+/, $inflected;
1720 my @words = map lc, split_name $table;
1721 my $as_phrase = join ' ', @words;
1723 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1725 return join '', map ucfirst, split /\W+/, $inflected;
1728 sub _table2moniker {
1729 my ( $self, $table ) = @_;
1733 if( ref $self->moniker_map eq 'HASH' ) {
1734 $moniker = $self->moniker_map->{$table};
1736 elsif( ref $self->moniker_map eq 'CODE' ) {
1737 $moniker = $self->moniker_map->($table);
1740 $moniker ||= $self->_default_table2moniker($table);
1745 sub _load_relationships {
1746 my ($self, $table) = @_;
1748 my $tbl_fk_info = $self->_table_fk_info($table);
1749 foreach my $fkdef (@$tbl_fk_info) {
1750 $fkdef->{remote_source} =
1751 $self->monikers->{delete $fkdef->{remote_table}};
1753 my $tbl_uniq_info = $self->_table_uniq_info($table);
1755 my $local_moniker = $self->monikers->{$table};
1756 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1758 foreach my $src_class (sort keys %$rel_stmts) {
1759 my $src_stmts = $rel_stmts->{$src_class};
1760 foreach my $stmt (@$src_stmts) {
1761 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1766 # Overload these in driver class:
1768 # Returns an arrayref of column names
1769 sub _table_columns { croak "ABSTRACT METHOD" }
1771 # Returns arrayref of pk col names
1772 sub _table_pk_info { croak "ABSTRACT METHOD" }
1774 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1775 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1777 # Returns an arrayref of foreign key constraints, each
1778 # being a hashref with 3 keys:
1779 # local_columns (arrayref), remote_columns (arrayref), remote_table
1780 sub _table_fk_info { croak "ABSTRACT METHOD" }
1782 # Returns an array of lower case table names
1783 sub _tables_list { croak "ABSTRACT METHOD" }
1785 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1791 # generate the pod for this statement, storing it with $self->_pod
1792 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
1794 my $args = dump(@_);
1795 $args = '(' . $args . ')' if @_ < 2;
1796 my $stmt = $method . $args . q{;};
1798 warn qq|$class\->$stmt\n| if $self->debug;
1799 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1803 # generates the accompanying pod for a DBIC class method statement,
1804 # storing it with $self->_pod
1810 if ( $method eq 'table' ) {
1812 my $pcm = $self->pod_comment_mode;
1813 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
1814 $comment = $self->__table_comment($table);
1815 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1816 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1817 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
1818 $self->_pod( $class, "=head1 NAME" );
1819 my $table_descr = $class;
1820 $table_descr .= " - " . $comment if $comment and $comment_in_name;
1821 $self->{_class2table}{ $class } = $table;
1822 $self->_pod( $class, $table_descr );
1823 if ($comment and $comment_in_desc) {
1824 $self->_pod( $class, "=head1 DESCRIPTION" );
1825 $self->_pod( $class, $comment );
1827 $self->_pod_cut( $class );
1828 } elsif ( $method eq 'add_columns' ) {
1829 $self->_pod( $class, "=head1 ACCESSORS" );
1830 my $col_counter = 0;
1832 while( my ($name,$attrs) = splice @cols,0,2 ) {
1834 $self->_pod( $class, '=head2 ' . $name );
1835 $self->_pod( $class,
1837 my $s = $attrs->{$_};
1838 $s = !defined $s ? 'undef' :
1839 length($s) == 0 ? '(empty string)' :
1840 ref($s) eq 'SCALAR' ? $$s :
1847 looks_like_number($s) ? $s :
1852 } sort keys %$attrs,
1855 if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter)) {
1856 $self->_pod( $class, $comment );
1859 $self->_pod_cut( $class );
1860 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1861 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1862 my ( $accessor, $rel_class ) = @_;
1863 $self->_pod( $class, "=head2 $accessor" );
1864 $self->_pod( $class, 'Type: ' . $method );
1865 $self->_pod( $class, "Related object: L<$rel_class>" );
1866 $self->_pod_cut( $class );
1867 $self->{_relations_started} { $class } = 1;
1871 sub _filter_comment {
1872 my ($self, $txt) = @_;
1874 $txt = '' if not defined $txt;
1876 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
1881 sub __table_comment {
1884 if (my $code = $self->can('_table_comment')) {
1885 return $self->_filter_comment($self->$code(@_));
1891 sub __column_comment {
1894 if (my $code = $self->can('_column_comment')) {
1895 return $self->_filter_comment($self->$code(@_));
1901 # Stores a POD documentation
1903 my ($self, $class, $stmt) = @_;
1904 $self->_raw_stmt( $class, "\n" . $stmt );
1908 my ($self, $class ) = @_;
1909 $self->_raw_stmt( $class, "\n=cut\n" );
1912 # Store a raw source line for a class (for dumping purposes)
1914 my ($self, $class, $stmt) = @_;
1915 push(@{$self->{_dump_storage}->{$class}}, $stmt);
1918 # Like above, but separately for the externally loaded stuff
1920 my ($self, $class, $stmt) = @_;
1921 push(@{$self->{_ext_storage}->{$class}}, $stmt);
1924 sub _quote_table_name {
1925 my ($self, $table) = @_;
1927 my $qt = $self->schema->storage->sql_maker->quote_char;
1929 return $table unless $qt;
1932 return $qt->[0] . $table . $qt->[1];
1935 return $qt . $table . $qt;
1938 sub _custom_column_info {
1939 my ( $self, $table_name, $column_name, $column_info ) = @_;
1941 if (my $code = $self->custom_column_info) {
1942 return $code->($table_name, $column_name, $column_info) || {};
1947 sub _datetime_column_info {
1948 my ( $self, $table_name, $column_name, $column_info ) = @_;
1950 my $type = $column_info->{data_type} || '';
1951 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
1952 or ($type =~ /date|timestamp/i)) {
1953 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
1954 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
1960 my ($self, $name) = @_;
1962 return $self->preserve_case ? $name : lc($name);
1966 my ($self, $name) = @_;
1968 return $self->preserve_case ? $name : uc($name);
1971 sub _unregister_source_for_table {
1972 my ($self, $table) = @_;
1976 my $schema = $self->schema;
1977 # in older DBIC it's a private method
1978 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
1979 $schema->$unregister($self->_table2moniker($table));
1980 delete $self->monikers->{$table};
1981 delete $self->classes->{$table};
1982 delete $self->_upgrading_classes->{$table};
1983 delete $self->{_tables}{$table};
1987 # remove the dump dir from @INC on destruction
1991 @INC = grep $_ ne $self->dump_directory, @INC;
1996 Returns a hashref of loaded table to moniker mappings. There will
1997 be two entries for each table, the original name and the "normalized"
1998 name, in the case that the two are different (such as databases
1999 that like uppercase table names, or preserve your original mixed-case
2000 definitions, or what-have-you).
2004 Returns a hashref of table to class mappings. In some cases it will
2005 contain multiple entries per table for the original and normalized table
2006 names, as above in L</monikers>.
2010 L<DBIx::Class::Schema::Loader>
2014 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2018 This library is free software; you can redistribute it and/or modify it under
2019 the same terms as Perl itself.
2024 # vim:et sts=4 sw=4 tw=0: