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 Scalar::Util 'looks_like_number';
20 use File::Slurp 'read_file';
21 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_package_without_redefine_warnings class_path/;
22 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
25 use Encode qw/encode/;
28 our $VERSION = '0.07010';
30 __PACKAGE__->mk_group_ro_accessors('simple', qw/
37 additional_base_classes
52 default_resultset_class
57 overwrite_modifications
79 __PACKAGE__->mk_group_accessors('simple', qw/
81 schema_version_to_dump
83 _upgrading_from_load_classes
84 _downgrading_to_load_classes
85 _rewriting_result_namespace
90 pod_comment_spillover_length
97 datetime_undef_if_invalid
104 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
108 See L<DBIx::Class::Schema::Loader>
112 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
113 classes, and implements the common functionality between them.
115 =head1 CONSTRUCTOR OPTIONS
117 These constructor options are the base options for
118 L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
120 =head2 skip_relationships
122 Skip setting up relationships. The default is to attempt the loading
125 =head2 skip_load_external
127 Skip loading of other classes in @INC. The default is to merge all other classes
128 with the same name found in @INC into the schema file we are creating.
132 Static schemas (ones dumped to disk) will, by default, use the new-style
133 relationship names and singularized Results, unless you're overwriting an
134 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
135 which case the backward compatible RelBuilder will be activated, and the
136 appropriate monikerization used.
142 will disable the backward-compatible RelBuilder and use
143 the new-style relationship names along with singularized Results, even when
144 overwriting a dump made with an earlier version.
146 The option also takes a hashref:
148 naming => { relationships => 'v7', monikers => 'v7' }
156 How to name relationship accessors.
160 How to name Result classes.
162 =item column_accessors
164 How to name column accessors in Result classes.
174 Latest style, whatever that happens to be.
178 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
182 Monikers singularized as whole words, C<might_have> relationships for FKs on
183 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
185 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
190 All monikers and relationships are inflected using
191 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
192 from relationship names.
194 In general, there is very little difference between v5 and v6 schemas.
198 This mode is identical to C<v6> mode, except that monikerization of CamelCase
199 table names is also done correctly.
201 CamelCase column names in case-preserving mode will also be handled correctly
202 for relationship name inflection. See L</preserve_case>.
204 In this mode, CamelCase L</column_accessors> are normalized based on case
205 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
207 If you don't have any CamelCase table or column names, you can upgrade without
208 breaking any of your code.
212 For L</monikers>, this option does not inflect the table names but makes
213 monikers based on the actual name. For L</column_accessors> this option does
214 not normalize CamelCase column names to lowercase column accessors, but makes
215 accessors that are the same names as the columns (with any non-\w chars
216 replaced with underscores.)
220 For L</monikers>, singularizes the names using the most current inflector. This
221 is the same as setting the option to L</current>.
225 For L</monikers>, pluralizes the names, using the most current inflector.
229 Dynamic schemas will always default to the 0.04XXX relationship names and won't
230 singularize Results for backward compatibility, to activate the new RelBuilder
231 and singularization put this in your C<Schema.pm> file:
233 __PACKAGE__->naming('current');
235 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
236 next major version upgrade:
238 __PACKAGE__->naming('v7');
242 By default POD will be generated for columns and relationships, using database
243 metadata for the text if available and supported.
245 Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
246 supported for Postgres right now.
248 Set this to C<0> to turn off all POD generation.
250 =head2 pod_comment_mode
252 Controls where table comments appear in the generated POD. Smaller table
253 comments are appended to the C<NAME> section of the documentation, and larger
254 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
255 section to be generated with the comment always, only use C<NAME>, or choose
256 the length threshold at which the comment is forced into the description.
262 Use C<NAME> section only.
266 Force C<DESCRIPTION> always.
270 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
275 =head2 pod_comment_spillover_length
277 When pod_comment_mode is set to C<auto>, this is the length of the comment at
278 which it will be forced into a separate description section.
282 =head2 relationship_attrs
284 Hashref of attributes to pass to each generated relationship, listed
285 by type. Also supports relationship type 'all', containing options to
286 pass to all generated relationships. Attributes set for more specific
287 relationship types override those set in 'all'.
291 relationship_attrs => {
292 belongs_to => { is_deferrable => 0 },
295 use this to turn off DEFERRABLE on your foreign key constraints.
299 If set to true, each constructive L<DBIx::Class> statement the loader
300 decides to execute will be C<warn>-ed before execution.
304 Set the name of the schema to load (schema in the sense that your database
305 vendor means it). Does not currently support loading more than one schema
310 Only load tables matching regex. Best specified as a qr// regex.
314 Exclude tables matching regex. Best specified as a qr// regex.
318 Overrides the default table name to moniker translation. Can be either
319 a hashref of table keys and moniker values, or a coderef for a translator
320 function taking a single scalar table name argument and returning
321 a scalar moniker. If the hash entry does not exist, or the function
322 returns a false value, the code falls back to default behavior
325 The default behavior is to split on case transition and non-alphanumeric
326 boundaries, singularize the resulting phrase, then join the titlecased words
329 Table Name | Moniker Name
330 ---------------------------------
332 luser_group | LuserGroup
333 luser-opts | LuserOpt
334 stations_visited | StationVisited
335 routeChange | RouteChange
337 =head2 col_accessor_map
339 Same as moniker_map, but for column accessor names. If a coderef is
340 passed, the code is called with arguments of
342 the name of the column in the underlying database,
343 default accessor name that DBICSL would ordinarily give this column,
345 table_class => name of the DBIC class we are building,
346 table_moniker => calculated moniker for this table (after moniker_map if present),
347 table_name => name of the database table,
348 full_table_name => schema-qualified name of the database table (RDBMS specific),
349 schema_class => name of the schema class we are building,
350 column_info => hashref of column info (data_type, is_nullable, etc),
353 =head2 inflect_plural
355 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
356 if hash key does not exist or coderef returns false), but acts as a map
357 for pluralizing relationship names. The default behavior is to utilize
358 L<Lingua::EN::Inflect::Phrase/to_PL>.
360 =head2 inflect_singular
362 As L</inflect_plural> above, but for singularizing relationship names.
363 Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
365 =head2 schema_base_class
367 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
369 =head2 result_base_class
371 Base class for your table classes (aka result classes). Defaults to
374 =head2 additional_base_classes
376 List of additional base classes all of your table classes will use.
378 =head2 left_base_classes
380 List of additional base classes all of your table classes will use
381 that need to be leftmost.
383 =head2 additional_classes
385 List of additional classes which all of your table classes will use.
389 List of additional components to be loaded into all of your table
390 classes. A good example would be
391 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
393 =head2 result_components_map
395 A hashref of moniker keys and component values. Unlike L</components>, which
396 loads the given components into every Result class, this option allows you to
397 load certain components for specified Result classes. For example:
399 result_components_map => {
400 StationVisited => '+YourApp::Schema::Component::StationVisited',
402 '+YourApp::Schema::Component::RouteChange',
403 'InflateColumn::DateTime',
407 You may use this in conjunction with L</components>.
411 List of L<Moose> roles to be applied to all of your Result classes.
413 =head2 result_roles_map
415 A hashref of moniker keys and role values. Unlike L</result_roles>, which
416 applies the given roles to every Result class, this option allows you to apply
417 certain roles for specified Result classes. For example:
419 result_roles_map => {
421 'YourApp::Role::Building',
422 'YourApp::Role::Destination',
424 RouteChange => 'YourApp::Role::TripEvent',
427 You may use this in conjunction with L</result_roles>.
429 =head2 use_namespaces
431 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
434 Generate result class names suitable for
435 L<DBIx::Class::Schema/load_namespaces> and call that instead of
436 L<DBIx::Class::Schema/load_classes>. When using this option you can also
437 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
438 C<resultset_namespace>, C<default_resultset_class>), and they will be added
439 to the call (and the generated result class names adjusted appropriately).
441 =head2 dump_directory
443 The value of this option is a perl libdir pathname. Within
444 that directory this module will create a baseline manual
445 L<DBIx::Class::Schema> module set, based on what it creates at runtime.
447 The created schema class will have the same classname as the one on
448 which you are setting this option (and the ResultSource classes will be
449 based on this name as well).
451 Normally you wouldn't hard-code this setting in your schema class, as it
452 is meant for one-time manual usage.
454 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
455 recommended way to access this functionality.
457 =head2 dump_overwrite
459 Deprecated. See L</really_erase_my_files> below, which does *not* mean
460 the same thing as the old C<dump_overwrite> setting from previous releases.
462 =head2 really_erase_my_files
464 Default false. If true, Loader will unconditionally delete any existing
465 files before creating the new ones from scratch when dumping a schema to disk.
467 The default behavior is instead to only replace the top portion of the
468 file, up to and including the final stanza which contains
469 C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
470 leaving any customizations you placed after that as they were.
472 When C<really_erase_my_files> is not set, if the output file already exists,
473 but the aforementioned final stanza is not found, or the checksum
474 contained there does not match the generated contents, Loader will
475 croak and not touch the file.
477 You should really be using version control on your schema classes (and all
478 of the rest of your code for that matter). Don't blame me if a bug in this
479 code wipes something out when it shouldn't have, you've been warned.
481 =head2 overwrite_modifications
483 Default false. If false, when updating existing files, Loader will
484 refuse to modify any Loader-generated code that has been modified
485 since its last run (as determined by the checksum Loader put in its
488 If true, Loader will discard any manual modifications that have been
489 made to Loader-generated code.
491 Again, you should be using version control on your schema classes. Be
492 careful with this option.
494 =head2 custom_column_info
496 Hook for adding extra attributes to the
497 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
499 Must be a coderef that returns a hashref with the extra attributes.
501 Receives the table name, column name and column_info.
505 custom_column_info => sub {
506 my ($table_name, $column_name, $column_info) = @_;
508 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
509 return { is_snoopy => 1 };
513 This attribute can also be used to set C<inflate_datetime> on a non-datetime
514 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
516 =head2 datetime_timezone
518 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
519 columns with the DATE/DATETIME/TIMESTAMP data_types.
521 =head2 datetime_locale
523 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
524 columns with the DATE/DATETIME/TIMESTAMP data_types.
526 =head2 datetime_undef_if_invalid
528 Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
529 datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
532 The default is recommended to deal with data such as C<00/00/00> which
533 sometimes ends up in such columns in MySQL.
537 File in Perl format, which should return a HASH reference, from which to read
542 Usually column names are lowercased, to make them easier to work with in
543 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
546 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
547 case-sensitive collation will turn this option on unconditionally.
549 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
552 =head2 qualify_objects
554 Set to true to prepend the L</db_schema> to table names for C<<
555 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
559 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
560 L<namespace::autoclean>. The default content after the md5 sum also makes the
563 It is safe to upgrade your existing Schema to this option.
565 =head2 col_collision_map
567 This option controls how accessors for column names which collide with perl
568 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
570 This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
571 strings which are compiled to regular expressions that map to
572 L<sprintf|perlfunc/sprintf> formats.
576 col_collision_map => 'column_%s'
578 col_collision_map => { '(.*)' => 'column_%s' }
580 col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
582 =head2 rel_collision_map
584 Works just like L</col_collision_map>, but for relationship names/accessors
585 rather than column names/accessors.
587 The default is to just append C<_rel> to the relationship name, see
588 L</RELATIONSHIP NAME COLLISIONS>.
590 =head2 uniq_to_primary
592 Automatically promotes the largest unique constraints on tables to primary
593 keys, assuming there is only one largest unique constraint.
597 None of these methods are intended for direct invocation by regular
598 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
599 L<DBIx::Class::Schema::Loader>.
603 my $CURRENT_V = 'v7';
606 schema_base_class result_base_class additional_base_classes
607 left_base_classes additional_classes components result_roles
610 # ensure that a peice of object data is a valid arrayref, creating
611 # an empty one or encapsulating whatever's there.
612 sub _ensure_arrayref {
617 $self->{$_} = [ $self->{$_} ]
618 unless ref $self->{$_} eq 'ARRAY';
624 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
625 by L<DBIx::Class::Schema::Loader>.
630 my ( $class, %args ) = @_;
632 if (exists $args{column_accessor_map}) {
633 $args{col_accessor_map} = delete $args{column_accessor_map};
636 my $self = { %args };
638 # don't lose undef options
639 for (values %$self) {
640 $_ = 0 unless defined $_;
643 bless $self => $class;
645 if (my $config_file = $self->config_file) {
646 my $config_opts = do $config_file;
648 croak "Error reading config from $config_file: $@" if $@;
650 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
652 while (my ($k, $v) = each %$config_opts) {
653 $self->{$k} = $v unless exists $self->{$k};
657 $self->result_components_map($self->{result_component_map})
658 if defined $self->{result_component_map};
660 $self->result_roles_map($self->{result_role_map})
661 if defined $self->{result_role_map};
663 croak "the result_roles and result_roles_map options may only be used in conjunction with use_moose=1"
664 if ((not defined $self->use_moose) || (not $self->use_moose))
665 && ((defined $self->result_roles) || (defined $self->result_roles_map));
667 $self->_ensure_arrayref(qw/additional_classes
668 additional_base_classes
674 $self->_validate_class_args;
676 croak "result_components_map must be a hash"
677 if defined $self->result_components_map
678 && ref $self->result_components_map ne 'HASH';
680 if ($self->result_components_map) {
681 my %rc_map = %{ $self->result_components_map };
682 foreach my $moniker (keys %rc_map) {
683 $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
685 $self->result_components_map(\%rc_map);
688 $self->result_components_map({});
690 $self->_validate_result_components_map;
692 croak "result_roles_map must be a hash"
693 if defined $self->result_roles_map
694 && ref $self->result_roles_map ne 'HASH';
696 if ($self->result_roles_map) {
697 my %rr_map = %{ $self->result_roles_map };
698 foreach my $moniker (keys %rr_map) {
699 $rr_map{$moniker} = [ $rr_map{$moniker} ] unless ref $rr_map{$moniker};
701 $self->result_roles_map(\%rr_map);
703 $self->result_roles_map({});
705 $self->_validate_result_roles_map;
707 if ($self->use_moose) {
708 if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
709 die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
710 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
714 $self->{monikers} = {};
715 $self->{tables} = {};
716 $self->{class_to_table} = {};
717 $self->{classes} = {};
718 $self->{_upgrading_classes} = {};
720 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
721 $self->{schema} ||= $self->{schema_class};
723 croak "dump_overwrite is deprecated. Please read the"
724 . " DBIx::Class::Schema::Loader::Base documentation"
725 if $self->{dump_overwrite};
727 $self->{dynamic} = ! $self->{dump_directory};
728 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
733 $self->{dump_directory} ||= $self->{temp_directory};
735 $self->real_dump_directory($self->{dump_directory});
737 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
738 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
740 if (not defined $self->naming) {
741 $self->naming_set(0);
744 $self->naming_set(1);
747 if ((not ref $self->naming) && defined $self->naming) {
748 my $naming_ver = $self->naming;
750 relationships => $naming_ver,
751 monikers => $naming_ver,
752 column_accessors => $naming_ver,
757 for (values %{ $self->naming }) {
758 $_ = $CURRENT_V if $_ eq 'current';
761 $self->{naming} ||= {};
763 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
764 croak 'custom_column_info must be a CODE ref';
767 $self->_check_back_compat;
769 $self->use_namespaces(1) unless defined $self->use_namespaces;
770 $self->generate_pod(1) unless defined $self->generate_pod;
771 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
772 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
774 if (my $col_collision_map = $self->col_collision_map) {
775 if (my $reftype = ref $col_collision_map) {
776 if ($reftype ne 'HASH') {
777 croak "Invalid type $reftype for option 'col_collision_map'";
781 $self->col_collision_map({ '(.*)' => $col_collision_map });
788 sub _check_back_compat {
791 # dynamic schemas will always be in 0.04006 mode, unless overridden
792 if ($self->dynamic) {
793 # just in case, though no one is likely to dump a dynamic schema
794 $self->schema_version_to_dump('0.04006');
796 if (not $self->naming_set) {
797 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
799 Dynamic schema detected, will run in 0.04006 mode.
801 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
802 to disable this warning.
804 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
809 $self->_upgrading_from('v4');
812 if ((not defined $self->use_namespaces) && ($self->naming_set)) {
813 $self->use_namespaces(1);
816 $self->naming->{relationships} ||= 'v4';
817 $self->naming->{monikers} ||= 'v4';
819 if ($self->use_namespaces) {
820 $self->_upgrading_from_load_classes(1);
823 $self->use_namespaces(0);
829 # otherwise check if we need backcompat mode for a static schema
830 my $filename = $self->get_dump_filename($self->schema_class);
831 return unless -e $filename;
833 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
834 $self->_parse_generated_file($filename);
836 return unless $old_ver;
838 # determine if the existing schema was dumped with use_moose => 1
839 if (! defined $self->use_moose) {
840 $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
843 my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
845 my $result_namespace = do { ($old_gen =~ /result_namespace => (.+)/) ? $1 : '' };
846 my $ds = eval $result_namespace;
848 Could not eval expression '$result_namespace' for result_namespace from
851 $result_namespace = $ds || '';
853 if ($load_classes && (not defined $self->use_namespaces)) {
854 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
856 'load_classes;' static schema detected, turning off 'use_namespaces'.
858 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
859 variable to disable this warning.
861 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
864 $self->use_namespaces(0);
866 elsif ($load_classes && $self->use_namespaces) {
867 $self->_upgrading_from_load_classes(1);
869 elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
870 $self->_downgrading_to_load_classes(
871 $result_namespace || 'Result'
874 elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
875 if (not $self->result_namespace) {
876 $self->result_namespace($result_namespace || 'Result');
878 elsif ($result_namespace ne $self->result_namespace) {
879 $self->_rewriting_result_namespace(
880 $result_namespace || 'Result'
885 # XXX when we go past .0 this will need fixing
886 my ($v) = $old_ver =~ /([1-9])/;
889 return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
891 if (not %{ $self->naming }) {
892 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
894 Version $old_ver static schema detected, turning on backcompat mode.
896 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
897 to disable this warning.
899 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
901 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
902 from version 0.04006.
905 $self->naming->{relationships} ||= $v;
906 $self->naming->{monikers} ||= $v;
907 $self->naming->{column_accessors} ||= $v;
909 $self->schema_version_to_dump($old_ver);
912 $self->_upgrading_from($v);
916 sub _validate_class_args {
919 foreach my $k (@CLASS_ARGS) {
920 next unless $self->$k;
922 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
923 $self->_validate_classes($k, \@classes);
927 sub _validate_result_components_map {
930 foreach my $classes (values %{ $self->result_components_map }) {
931 $self->_validate_classes('result_components_map', $classes);
935 sub _validate_result_roles_map {
938 foreach my $classes (values %{ $self->result_roles_map }) {
939 $self->_validate_classes('result_roles_map', $classes);
943 sub _validate_classes {
948 # make a copy to not destroy original
949 my @classes = @$classes;
951 foreach my $c (@classes) {
952 # components default to being under the DBIx::Class namespace unless they
953 # are preceeded with a '+'
954 if ( $key =~ m/component/ && $c !~ s/^\+// ) {
955 $c = 'DBIx::Class::' . $c;
958 # 1 == installed, 0 == not installed, undef == invalid classname
959 my $installed = Class::Inspector->installed($c);
960 if ( defined($installed) ) {
961 if ( $installed == 0 ) {
962 croak qq/$c, as specified in the loader option "$key", is not installed/;
965 croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
971 sub _find_file_in_inc {
972 my ($self, $file) = @_;
974 foreach my $prefix (@INC) {
975 my $fullpath = File::Spec->catfile($prefix, $file);
976 return $fullpath if -f $fullpath
977 # abs_path throws on Windows for nonexistant files
978 and (try { Cwd::abs_path($fullpath) }) ne
979 ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
985 sub _find_class_in_inc {
986 my ($self, $class) = @_;
988 return $self->_find_file_in_inc(class_path($class));
994 return $self->_upgrading_from
995 || $self->_upgrading_from_load_classes
996 || $self->_downgrading_to_load_classes
997 || $self->_rewriting_result_namespace
1001 sub _rewrite_old_classnames {
1002 my ($self, $code) = @_;
1004 return $code unless $self->_rewriting;
1006 my %old_classes = reverse %{ $self->_upgrading_classes };
1008 my $re = join '|', keys %old_classes;
1009 $re = qr/\b($re)\b/;
1011 $code =~ s/$re/$old_classes{$1} || $1/eg;
1016 sub _load_external {
1017 my ($self, $class) = @_;
1019 return if $self->{skip_load_external};
1021 # so that we don't load our own classes, under any circumstances
1022 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
1024 my $real_inc_path = $self->_find_class_in_inc($class);
1026 my $old_class = $self->_upgrading_classes->{$class}
1027 if $self->_rewriting;
1029 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
1030 if $old_class && $old_class ne $class;
1032 return unless $real_inc_path || $old_real_inc_path;
1034 if ($real_inc_path) {
1035 # If we make it to here, we loaded an external definition
1036 warn qq/# Loaded external class definition for '$class'\n/
1039 my $code = $self->_rewrite_old_classnames(scalar read_file($real_inc_path, binmode => ':encoding(UTF-8)'));
1041 if ($self->dynamic) { # load the class too
1042 eval_package_without_redefine_warnings($class, $code);
1045 $self->_ext_stmt($class,
1046 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
1047 .qq|# They are now part of the custom portion of this file\n|
1048 .qq|# for you to hand-edit. If you do not either delete\n|
1049 .qq|# this section or remove that file from \@INC, this section\n|
1050 .qq|# will be repeated redundantly when you re-create this\n|
1051 .qq|# file again via Loader! See skip_load_external to disable\n|
1052 .qq|# this feature.\n|
1055 $self->_ext_stmt($class, $code);
1056 $self->_ext_stmt($class,
1057 qq|# End of lines loaded from '$real_inc_path' |
1061 if ($old_real_inc_path) {
1062 my $code = read_file($old_real_inc_path, binmode => ':encoding(UTF-8)');
1064 $self->_ext_stmt($class, <<"EOF");
1066 # These lines were loaded from '$old_real_inc_path',
1067 # based on the Result class name that would have been created by an older
1068 # version of the Loader. For a static schema, this happens only once during
1069 # upgrade. See skip_load_external to disable this feature.
1072 $code = $self->_rewrite_old_classnames($code);
1074 if ($self->dynamic) {
1077 Detected external content in '$old_real_inc_path', a class name that would have
1078 been used by an older version of the Loader.
1080 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
1081 new name of the Result.
1083 eval_package_without_redefine_warnings($class, $code);
1087 $self->_ext_stmt($class, $code);
1088 $self->_ext_stmt($class,
1089 qq|# End of lines loaded from '$old_real_inc_path' |
1096 Does the actual schema-construction work.
1103 $self->_load_tables(
1104 $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1112 Rescan the database for changes. Returns a list of the newly added table
1115 The schema argument should be the schema class or object to be affected. It
1116 should probably be derived from the original schema_class used during L</load>.
1121 my ($self, $schema) = @_;
1123 $self->{schema} = $schema;
1124 $self->_relbuilder->{schema} = $schema;
1127 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
1129 foreach my $table (@current) {
1130 if(!exists $self->{_tables}->{$table}) {
1131 push(@created, $table);
1136 @current{@current} = ();
1137 foreach my $table (keys %{ $self->{_tables} }) {
1138 if (not exists $current{$table}) {
1139 $self->_unregister_source_for_table($table);
1143 delete @$self{qw/_dump_storage _relations_started _uniqs_started/};
1145 my $loaded = $self->_load_tables(@current);
1147 return map { $self->monikers->{$_} } @created;
1153 return if $self->{skip_relationships};
1155 return $self->{relbuilder} ||= do {
1157 no warnings 'uninitialized';
1158 my $relbuilder_suff =
1164 ->{ $self->naming->{relationships}};
1166 my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1167 $self->ensure_class_loaded($relbuilder_class);
1168 $relbuilder_class->new( $self );
1174 my ($self, @tables) = @_;
1176 # Save the new tables to the tables list
1178 $self->{_tables}->{$_} = 1;
1181 $self->_make_src_class($_) for @tables;
1183 # sanity-check for moniker clashes
1184 my $inverse_moniker_idx;
1185 for (keys %{$self->monikers}) {
1186 push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1190 for (keys %$inverse_moniker_idx) {
1191 my $tables = $inverse_moniker_idx->{$_};
1193 push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1194 join (', ', map { "'$_'" } @$tables),
1201 die 'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1202 . 'Either change the naming style, or supply an explicit moniker_map: '
1203 . join ('; ', @clashes)
1209 $self->_setup_src_meta($_) for @tables;
1211 if(!$self->skip_relationships) {
1212 # The relationship loader needs a working schema
1214 local $self->{dump_directory} = $self->{temp_directory};
1215 $self->_reload_classes(\@tables);
1216 $self->_load_relationships(\@tables);
1219 # Remove that temp dir from INC so it doesn't get reloaded
1220 @INC = grep $_ ne $self->dump_directory, @INC;
1223 $self->_load_roles($_) for @tables;
1225 $self->_load_external($_)
1226 for map { $self->classes->{$_} } @tables;
1228 # Reload without unloading first to preserve any symbols from external
1230 $self->_reload_classes(\@tables, { unload => 0 });
1232 # Drop temporary cache
1233 delete $self->{_cache};
1238 sub _reload_classes {
1239 my ($self, $tables, $opts) = @_;
1241 my @tables = @$tables;
1243 my $unload = $opts->{unload};
1244 $unload = 1 unless defined $unload;
1246 # so that we don't repeat custom sections
1247 @INC = grep $_ ne $self->dump_directory, @INC;
1249 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1251 unshift @INC, $self->dump_directory;
1254 my %have_source = map { $_ => $self->schema->source($_) }
1255 $self->schema->sources;
1257 for my $table (@tables) {
1258 my $moniker = $self->monikers->{$table};
1259 my $class = $self->classes->{$table};
1262 no warnings 'redefine';
1263 local *Class::C3::reinitialize = sub {}; # to speed things up, reinitialized below
1266 if (my $mc = $self->_moose_metaclass($class)) {
1269 Class::Unload->unload($class) if $unload;
1270 my ($source, $resultset_class);
1272 ($source = $have_source{$moniker})
1273 && ($resultset_class = $source->resultset_class)
1274 && ($resultset_class ne 'DBIx::Class::ResultSet')
1276 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1277 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1280 Class::Unload->unload($resultset_class) if $unload;
1281 $self->_reload_class($resultset_class) if $has_file;
1283 $self->_reload_class($class);
1285 push @to_register, [$moniker, $class];
1288 Class::C3->reinitialize;
1289 for (@to_register) {
1290 $self->schema->register_class(@$_);
1294 sub _moose_metaclass {
1295 return undef unless $INC{'Class/MOP.pm'}; # if CMOP is not loaded the class could not have loaded in the 1st place
1299 my $mc = try { Class::MOP::class_of($class) }
1302 return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1305 # We use this instead of ensure_class_loaded when there are package symbols we
1308 my ($self, $class) = @_;
1310 delete $INC{ +class_path($class) };
1313 eval_package_without_redefine_warnings ($class, "require $class");
1316 my $source = read_file($self->_get_dump_filename($class), binmode => ':encoding(UTF-8)');
1317 die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
1321 sub _get_dump_filename {
1322 my ($self, $class) = (@_);
1324 $class =~ s{::}{/}g;
1325 return $self->dump_directory . q{/} . $class . q{.pm};
1328 =head2 get_dump_filename
1332 Returns the full path to the file for a class that the class has been or will
1333 be dumped to. This is a file in a temp dir for a dynamic schema.
1337 sub get_dump_filename {
1338 my ($self, $class) = (@_);
1340 local $self->{dump_directory} = $self->real_dump_directory;
1342 return $self->_get_dump_filename($class);
1345 sub _ensure_dump_subdirs {
1346 my ($self, $class) = (@_);
1348 my @name_parts = split(/::/, $class);
1349 pop @name_parts; # we don't care about the very last element,
1350 # which is a filename
1352 my $dir = $self->dump_directory;
1355 mkdir($dir) or croak "mkdir('$dir') failed: $!";
1357 last if !@name_parts;
1358 $dir = File::Spec->catdir($dir, shift @name_parts);
1363 my ($self, @classes) = @_;
1365 my $schema_class = $self->schema_class;
1366 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1368 my $target_dir = $self->dump_directory;
1369 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1370 unless $self->{dynamic} or $self->{quiet};
1373 qq|package $schema_class;\n\n|
1374 . qq|# Created by DBIx::Class::Schema::Loader\n|
1375 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1377 if ($self->use_moose) {
1378 $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1381 $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
1384 if ($self->use_namespaces) {
1385 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1386 my $namespace_options;
1388 my @attr = qw/resultset_namespace default_resultset_class/;
1390 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1392 for my $attr (@attr) {
1394 my $code = dumper_squashed $self->$attr;
1395 $namespace_options .= qq| $attr => $code,\n|
1398 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1399 $schema_text .= qq|;\n|;
1402 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1406 local $self->{version_to_dump} = $self->schema_version_to_dump;
1407 $self->_write_classfile($schema_class, $schema_text, 1);
1410 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1412 foreach my $src_class (@classes) {
1414 qq|package $src_class;\n\n|
1415 . qq|# Created by DBIx::Class::Schema::Loader\n|
1416 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1418 $src_text .= $self->_make_pod_heading($src_class);
1420 $src_text .= qq|use strict;\nuse warnings;\n\n|;
1422 $src_text .= $self->_base_class_pod($result_base_class)
1423 unless $result_base_class eq 'DBIx::Class::Core';
1425 if ($self->use_moose) {
1426 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1428 # these options 'use base' which is compile time
1429 if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1430 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n|;
1433 $src_text .= qq|\nextends '$result_base_class';\n|;
1437 $src_text .= qq|use base '$result_base_class';\n|;
1440 $self->_write_classfile($src_class, $src_text);
1443 # remove Result dir if downgrading from use_namespaces, and there are no
1445 if (my $result_ns = $self->_downgrading_to_load_classes
1446 || $self->_rewriting_result_namespace) {
1447 my $result_namespace = $self->_result_namespace(
1452 (my $result_dir = $result_namespace) =~ s{::}{/}g;
1453 $result_dir = $self->dump_directory . '/' . $result_dir;
1455 unless (my @files = glob "$result_dir/*") {
1460 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1465 my ($self, $version, $ts) = @_;
1466 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1469 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1472 sub _write_classfile {
1473 my ($self, $class, $text, $is_schema) = @_;
1475 my $filename = $self->_get_dump_filename($class);
1476 $self->_ensure_dump_subdirs($class);
1478 if (-f $filename && $self->really_erase_my_files) {
1479 warn "Deleting existing file '$filename' due to "
1480 . "'really_erase_my_files' setting\n" unless $self->{quiet};
1484 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1485 = $self->_parse_generated_file($filename);
1487 if (! $old_gen && -f $filename) {
1488 croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1489 . " it does not appear to have been generated by Loader"
1492 my $custom_content = $old_custom || '';
1494 # prepend extra custom content from a *renamed* class (singularization effect)
1495 if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1496 my $old_filename = $self->_get_dump_filename($renamed_class);
1498 if (-f $old_filename) {
1499 my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1501 $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1503 $custom_content = join ("\n", '', $extra_custom, $custom_content)
1506 unlink $old_filename;
1510 $custom_content ||= $self->_default_custom_content($is_schema);
1512 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1513 # If there is already custom content, which does not have the Moose content, add it.
1514 if ($self->use_moose) {
1516 my $non_moose_custom_content = do {
1517 local $self->{use_moose} = 0;
1518 $self->_default_custom_content;
1521 if ($custom_content eq $non_moose_custom_content) {
1522 $custom_content = $self->_default_custom_content($is_schema);
1524 elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1525 $custom_content .= $self->_default_custom_content($is_schema);
1528 elsif (defined $self->use_moose && $old_gen) {
1529 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'
1530 if $old_gen =~ /use \s+ MooseX?\b/x;
1533 $custom_content = $self->_rewrite_old_classnames($custom_content);
1536 for @{$self->{_dump_storage}->{$class} || []};
1538 # Check and see if the dump is infact differnt
1542 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1543 if (Digest::MD5::md5_base64(encode 'UTF-8', $compare_to) eq $old_md5) {
1544 return unless $self->_upgrading_from && $is_schema;
1548 $text .= $self->_sig_comment(
1549 $self->version_to_dump,
1550 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1553 open(my $fh, '>:encoding(UTF-8)', $filename)
1554 or croak "Cannot open '$filename' for writing: $!";
1556 # Write the top half and its MD5 sum
1557 print $fh $text . Digest::MD5::md5_base64(encode 'UTF-8', $text) . "\n";
1559 # Write out anything loaded via external partial class file in @INC
1561 for @{$self->{_ext_storage}->{$class} || []};
1563 # Write out any custom content the user has added
1564 print $fh $custom_content;
1567 or croak "Error closing '$filename': $!";
1570 sub _default_moose_custom_content {
1571 my ($self, $is_schema) = @_;
1573 if (not $is_schema) {
1574 return qq|\n__PACKAGE__->meta->make_immutable;|;
1577 return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
1580 sub _default_custom_content {
1581 my ($self, $is_schema) = @_;
1582 my $default = qq|\n\n# You can replace this text with custom|
1583 . qq| code or comments, and it will be preserved on regeneration|;
1584 if ($self->use_moose) {
1585 $default .= $self->_default_moose_custom_content($is_schema);
1587 $default .= qq|\n1;\n|;
1591 sub _parse_generated_file {
1592 my ($self, $fn) = @_;
1594 return unless -f $fn;
1596 open(my $fh, '<:encoding(UTF-8)', $fn)
1597 or croak "Cannot open '$fn' for reading: $!";
1600 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1602 my ($md5, $ts, $ver, $gen);
1608 # Pull out the version and timestamp from the line above
1609 ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
1612 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"
1613 if !$self->overwrite_modifications && Digest::MD5::md5_base64(encode 'UTF-8', $gen) ne $md5;
1622 my $custom = do { local $/; <$fh> }
1627 return ($gen, $md5, $ver, $ts, $custom);
1635 warn "$target: use $_;" if $self->debug;
1636 $self->_raw_stmt($target, "use $_;");
1644 my $blist = join(q{ }, @_);
1646 return unless $blist;
1648 warn "$target: use base qw/$blist/;" if $self->debug;
1649 $self->_raw_stmt($target, "use base qw/$blist/;");
1656 my $rlist = join(q{, }, map { qq{'$_'} } @_);
1658 return unless $rlist;
1660 warn "$target: with $rlist;" if $self->debug;
1661 $self->_raw_stmt($target, "\nwith $rlist;");
1664 sub _result_namespace {
1665 my ($self, $schema_class, $ns) = @_;
1666 my @result_namespace;
1668 $ns = $ns->[0] if ref $ns;
1670 if ($ns =~ /^\+(.*)/) {
1671 # Fully qualified namespace
1672 @result_namespace = ($1)
1675 # Relative namespace
1676 @result_namespace = ($schema_class, $ns);
1679 return wantarray ? @result_namespace : join '::', @result_namespace;
1682 # Create class with applicable bases, setup monikers, etc
1683 sub _make_src_class {
1684 my ($self, $table) = @_;
1686 my $schema = $self->schema;
1687 my $schema_class = $self->schema_class;
1689 my $table_moniker = $self->_table2moniker($table);
1690 my @result_namespace = ($schema_class);
1691 if ($self->use_namespaces) {
1692 my $result_namespace = $self->result_namespace || 'Result';
1693 @result_namespace = $self->_result_namespace(
1698 my $table_class = join(q{::}, @result_namespace, $table_moniker);
1700 if ((my $upgrading_v = $self->_upgrading_from)
1701 || $self->_rewriting) {
1702 local $self->naming->{monikers} = $upgrading_v
1705 my @result_namespace = @result_namespace;
1706 if ($self->_upgrading_from_load_classes) {
1707 @result_namespace = ($schema_class);
1709 elsif (my $ns = $self->_downgrading_to_load_classes) {
1710 @result_namespace = $self->_result_namespace(
1715 elsif ($ns = $self->_rewriting_result_namespace) {
1716 @result_namespace = $self->_result_namespace(
1722 my $old_class = join(q{::}, @result_namespace,
1723 $self->_table2moniker($table));
1725 $self->_upgrading_classes->{$table_class} = $old_class
1726 unless $table_class eq $old_class;
1729 $self->classes->{$table} = $table_class;
1730 $self->monikers->{$table} = $table_moniker;
1731 $self->tables->{$table_moniker} = $table;
1732 $self->class_to_table->{$table_class} = $table;
1734 $self->_pod_class_list($table_class, 'ADDITIONAL CLASSES USED', @{$self->additional_classes});
1736 $self->_use ($table_class, @{$self->additional_classes});
1738 $self->_pod_class_list($table_class, 'LEFT BASE CLASSES', @{$self->left_base_classes});
1740 $self->_inject($table_class, @{$self->left_base_classes});
1742 my @components = @{ $self->components || [] };
1744 push @components, @{ $self->result_components_map->{$table_moniker} }
1745 if exists $self->result_components_map->{$table_moniker};
1747 my @fq_components = @components;
1748 foreach my $component (@fq_components) {
1749 if ($component !~ s/^\+//) {
1750 $component = "DBIx::Class::$component";
1754 $self->_pod_class_list($table_class, 'COMPONENTS LOADED', @fq_components);
1756 $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
1758 $self->_pod_class_list($table_class, 'ADDITIONAL BASE CLASSES', @{$self->additional_base_classes});
1760 $self->_inject($table_class, @{$self->additional_base_classes});
1763 sub _is_result_class_method {
1764 my ($self, $name, $table_name) = @_;
1766 my $table_moniker = $table_name ? $self->monikers->{$table_name} : '';
1768 $self->_result_class_methods({})
1769 if not defined $self->_result_class_methods;
1771 if (not exists $self->_result_class_methods->{$table_moniker}) {
1772 my (@methods, %methods);
1773 my $base = $self->result_base_class || 'DBIx::Class::Core';
1775 my @components = @{ $self->components || [] };
1777 push @components, @{ $self->result_components_map->{$table_moniker} }
1778 if exists $self->result_components_map->{$table_moniker};
1780 for my $c (@components) {
1781 $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
1784 my @roles = @{ $self->result_roles || [] };
1786 push @roles, @{ $self->result_roles_map->{$table_moniker} }
1787 if exists $self->result_roles_map->{$table_moniker};
1789 for my $class ($base, @components,
1790 ($self->use_moose ? 'Moose::Object' : ()), @roles) {
1791 $self->ensure_class_loaded($class);
1793 push @methods, @{ Class::Inspector->methods($class) || [] };
1796 push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
1798 @methods{@methods} = ();
1800 $self->_result_class_methods->{$table_moniker} = \%methods;
1802 my $result_methods = $self->_result_class_methods->{$table_moniker};
1804 return exists $result_methods->{$name};
1807 sub _resolve_col_accessor_collisions {
1808 my ($self, $table, $col_info) = @_;
1810 my $table_name = ref $table ? $$table : $table;
1812 while (my ($col, $info) = each %$col_info) {
1813 my $accessor = $info->{accessor} || $col;
1815 next if $accessor eq 'id'; # special case (very common column)
1817 if ($self->_is_result_class_method($accessor, $table_name)) {
1820 if (my $map = $self->col_collision_map) {
1821 for my $re (keys %$map) {
1822 if (my @matches = $col =~ /$re/) {
1823 $info->{accessor} = sprintf $map->{$re}, @matches;
1831 Column '$col' in table '$table_name' collides with an inherited method.
1832 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1834 $info->{accessor} = undef;
1840 # use the same logic to run moniker_map, col_accessor_map, and
1841 # relationship_name_map
1843 my ( $self, $map, $default_code, $ident, @extra ) = @_;
1845 my $default_ident = $default_code->( $ident, @extra );
1847 if( $map && ref $map eq 'HASH' ) {
1848 $new_ident = $map->{ $ident };
1850 elsif( $map && ref $map eq 'CODE' ) {
1851 $new_ident = $map->( $ident, $default_ident, @extra );
1854 $new_ident ||= $default_ident;
1859 sub _default_column_accessor_name {
1860 my ( $self, $column_name ) = @_;
1862 my $accessor_name = $column_name;
1863 $accessor_name =~ s/\W+/_/g;
1865 if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
1866 # older naming just lc'd the col accessor and that's all.
1867 return lc $accessor_name;
1869 elsif (($self->naming->{column_accessors}||'') eq 'preserve') {
1870 return $accessor_name;
1873 return join '_', map lc, split_name $column_name;
1876 sub _make_column_accessor_name {
1877 my ($self, $column_name, $column_context_info ) = @_;
1879 my $accessor = $self->_run_user_map(
1880 $self->col_accessor_map,
1881 sub { $self->_default_column_accessor_name( shift ) },
1883 $column_context_info,
1890 my ($self, $identifier) = @_;
1892 my $qt = $self->schema->storage->sql_maker->quote_char || '';
1895 return $qt->[0] . $identifier . $qt->[1];
1898 return "${qt}${identifier}${qt}";
1901 # Set up metadata (cols, pks, etc)
1902 sub _setup_src_meta {
1903 my ($self, $table) = @_;
1905 my $schema = $self->schema;
1906 my $schema_class = $self->schema_class;
1908 my $table_class = $self->classes->{$table};
1909 my $table_moniker = $self->monikers->{$table};
1911 my $table_name = $table;
1913 my $sql_maker = $self->schema->storage->sql_maker;
1914 my $name_sep = $sql_maker->name_sep;
1916 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1917 $table_name = \ $self->_quote($table_name);
1920 my $full_table_name = ($self->qualify_objects ?
1921 ($self->_quote($self->db_schema) . '.') : '')
1922 . (ref $table_name ? $$table_name : $table_name);
1924 # be careful to not create refs Data::Dump can "optimize"
1925 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1927 $self->_dbic_stmt($table_class, 'table', $full_table_name);
1929 my $cols = $self->_table_columns($table);
1930 my $col_info = $self->__columns_info_for($table);
1932 ### generate all the column accessor names
1933 while (my ($col, $info) = each %$col_info) {
1934 # hashref of other info that could be used by
1935 # user-defined accessor map functions
1937 table_class => $table_class,
1938 table_moniker => $table_moniker,
1939 table_name => $table_name,
1940 full_table_name => $full_table_name,
1941 schema_class => $schema_class,
1942 column_info => $info,
1945 $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
1948 $self->_resolve_col_accessor_collisions($table, $col_info);
1950 # prune any redundant accessor names
1951 while (my ($col, $info) = each %$col_info) {
1952 no warnings 'uninitialized';
1953 delete $info->{accessor} if $info->{accessor} eq $col;
1956 my $fks = $self->_table_fk_info($table);
1958 foreach my $fkdef (@$fks) {
1959 for my $col (@{ $fkdef->{local_columns} }) {
1960 $col_info->{$col}{is_foreign_key} = 1;
1964 my $pks = $self->_table_pk_info($table) || [];
1966 my %uniq_tag; # used to eliminate duplicate uniqs
1968 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1970 my $uniqs = $self->_table_uniq_info($table) || [];
1973 foreach my $uniq (@$uniqs) {
1974 my ($name, $cols) = @$uniq;
1975 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1976 push @uniqs, [$name, $cols];
1979 if ((not @$pks) && @uniqs && $self->uniq_to_primary) {
1980 my @by_colnum = sort { $b->[0] <=> $a->[0] }
1981 map [ scalar @{ $_->[1] }, $_ ], @uniqs;
1983 if (not (@by_colnum > 1 && $by_colnum[0][0] == $by_colnum[1][0])) {
1984 @uniqs = map $_->[1], @by_colnum;
1986 $pks = (shift @uniqs)->[1];
1990 foreach my $pkcol (@$pks) {
1991 $col_info->{$pkcol}{is_nullable} = 0;
1997 map { $_, ($col_info->{$_}||{}) } @$cols
2000 $self->_dbic_stmt($table_class, 'set_primary_key', @$pks)
2003 foreach my $uniq (@uniqs) {
2004 my ($name, $cols) = @$uniq;
2005 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
2009 sub __columns_info_for {
2010 my ($self, $table) = @_;
2012 my $result = $self->_columns_info_for($table);
2014 while (my ($col, $info) = each %$result) {
2015 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
2016 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
2018 $result->{$col} = $info;
2026 Returns a sorted list of loaded tables, using the original database table
2034 return keys %{$self->_tables};
2037 # Make a moniker from a table
2038 sub _default_table2moniker {
2039 no warnings 'uninitialized';
2040 my ($self, $table) = @_;
2042 if ($self->naming->{monikers} eq 'v4') {
2043 return join '', map ucfirst, split /[\W_]+/, lc $table;
2045 elsif ($self->naming->{monikers} eq 'v5') {
2046 return join '', map ucfirst, split /[\W_]+/,
2047 Lingua::EN::Inflect::Number::to_S(lc $table);
2049 elsif ($self->naming->{monikers} eq 'v6') {
2050 (my $as_phrase = lc $table) =~ s/_+/ /g;
2051 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
2053 return join '', map ucfirst, split /\W+/, $inflected;
2056 my @words = map lc, split_name $table;
2057 my $as_phrase = join ' ', @words;
2059 my $inflected = $self->naming->{monikers} eq 'plural' ?
2060 Lingua::EN::Inflect::Phrase::to_PL($as_phrase)
2062 $self->naming->{monikers} eq 'preserve' ?
2065 Lingua::EN::Inflect::Phrase::to_S($as_phrase);
2067 return join '', map ucfirst, split /\W+/, $inflected;
2070 sub _table2moniker {
2071 my ( $self, $table ) = @_;
2073 $self->_run_user_map(
2075 sub { $self->_default_table2moniker( shift ) },
2080 sub _load_relationships {
2081 my ($self, $tables) = @_;
2085 foreach my $table (@$tables) {
2086 my $tbl_fk_info = $self->_table_fk_info($table);
2087 foreach my $fkdef (@$tbl_fk_info) {
2088 $fkdef->{remote_source} =
2089 $self->monikers->{delete $fkdef->{remote_table}};
2091 my $tbl_uniq_info = $self->_table_uniq_info($table);
2093 my $local_moniker = $self->monikers->{$table};
2095 push @tables, [ $local_moniker, $tbl_fk_info, $tbl_uniq_info ];
2098 my $rel_stmts = $self->_relbuilder->generate_code(\@tables);
2100 foreach my $src_class (sort keys %$rel_stmts) {
2101 my $src_stmts = $rel_stmts->{$src_class};
2102 foreach my $stmt (@$src_stmts) {
2103 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
2109 my ($self, $table) = @_;
2111 my $table_moniker = $self->monikers->{$table};
2112 my $table_class = $self->classes->{$table};
2114 my @roles = @{ $self->result_roles || [] };
2115 push @roles, @{ $self->result_roles_map->{$table_moniker} }
2116 if exists $self->result_roles_map->{$table_moniker};
2119 $self->_pod_class_list($table_class, 'L<Moose> ROLES APPLIED', @roles);
2121 $self->_with($table_class, @roles);
2125 # Overload these in driver class:
2127 # Returns an arrayref of column names
2128 sub _table_columns { croak "ABSTRACT METHOD" }
2130 # Returns arrayref of pk col names
2131 sub _table_pk_info { croak "ABSTRACT METHOD" }
2133 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
2134 sub _table_uniq_info { croak "ABSTRACT METHOD" }
2136 # Returns an arrayref of foreign key constraints, each
2137 # being a hashref with 3 keys:
2138 # local_columns (arrayref), remote_columns (arrayref), remote_table
2139 sub _table_fk_info { croak "ABSTRACT METHOD" }
2141 # Returns an array of lower case table names
2142 sub _tables_list { croak "ABSTRACT METHOD" }
2144 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
2150 # generate the pod for this statement, storing it with $self->_pod
2151 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
2153 my $args = dump(@_);
2154 $args = '(' . $args . ')' if @_ < 2;
2155 my $stmt = $method . $args . q{;};
2157 warn qq|$class\->$stmt\n| if $self->debug;
2158 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
2162 sub _make_pod_heading {
2163 my ($self, $class) = @_;
2165 return '' if not $self->generate_pod;
2167 my $table = $self->class_to_table->{$class};
2170 my $pcm = $self->pod_comment_mode;
2171 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
2172 $comment = $self->__table_comment($table);
2173 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
2174 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
2175 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
2177 $pod .= "=head1 NAME\n\n";
2179 my $table_descr = $class;
2180 $table_descr .= " - " . $comment if $comment and $comment_in_name;
2182 $pod .= "$table_descr\n\n";
2184 if ($comment and $comment_in_desc) {
2185 $pod .= "=head1 DESCRIPTION\n\n${comment}\n\n";
2192 # generates the accompanying pod for a DBIC class method statement,
2193 # storing it with $self->_pod
2199 if ($method eq 'table') {
2201 $self->_pod($class, "=head1 TABLE: C<$table>");
2202 $self->_pod_cut($class);
2204 elsif ( $method eq 'add_columns' ) {
2205 $self->_pod( $class, "=head1 ACCESSORS" );
2206 my $col_counter = 0;
2208 while( my ($name,$attrs) = splice @cols,0,2 ) {
2210 $self->_pod( $class, '=head2 ' . $name );
2211 $self->_pod( $class,
2213 my $s = $attrs->{$_};
2214 $s = !defined $s ? 'undef' :
2215 length($s) == 0 ? '(empty string)' :
2216 ref($s) eq 'SCALAR' ? $$s :
2217 ref($s) ? dumper_squashed $s :
2218 looks_like_number($s) ? $s : qq{'$s'};
2221 } sort keys %$attrs,
2223 if (my $comment = $self->__column_comment($self->class_to_table->{$class}, $col_counter, $name)) {
2224 $self->_pod( $class, $comment );
2227 $self->_pod_cut( $class );
2228 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2229 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2230 my ( $accessor, $rel_class ) = @_;
2231 $self->_pod( $class, "=head2 $accessor" );
2232 $self->_pod( $class, 'Type: ' . $method );
2233 $self->_pod( $class, "Related object: L<$rel_class>" );
2234 $self->_pod_cut( $class );
2235 $self->{_relations_started} { $class } = 1;
2237 elsif ($method eq 'add_unique_constraint') {
2238 $self->_pod($class, '=head1 UNIQUE CONSTRAINTS')
2239 unless $self->{_uniqs_started}{$class};
2241 my ($name, $cols) = @_;
2243 $self->_pod($class, "=head2 C<$name>");
2244 $self->_pod($class, '=over 4');
2246 foreach my $col (@$cols) {
2247 $self->_pod($class, "=item \* L</$col>");
2250 $self->_pod($class, '=back');
2251 $self->_pod_cut($class);
2253 $self->{_uniqs_started}{$class} = 1;
2255 elsif ($method eq 'set_primary_key') {
2256 $self->_pod($class, "=head1 PRIMARY KEY");
2257 $self->_pod($class, '=over 4');
2259 foreach my $col (@_) {
2260 $self->_pod($class, "=item \* L</$col>");
2263 $self->_pod($class, '=back');
2264 $self->_pod_cut($class);
2268 sub _pod_class_list {
2269 my ($self, $class, $title, @classes) = @_;
2271 return unless @classes && $self->generate_pod;
2273 $self->_pod($class, "=head1 $title");
2274 $self->_pod($class, '=over 4');
2276 foreach my $link (@classes) {
2277 $self->_pod($class, "=item * L<$link>");
2280 $self->_pod($class, '=back');
2281 $self->_pod_cut($class);
2284 sub _base_class_pod {
2285 my ($self, $base_class) = @_;
2287 return unless $self->generate_pod;
2290 =head1 BASE CLASS: L<$base_class>
2297 sub _filter_comment {
2298 my ($self, $txt) = @_;
2300 $txt = '' if not defined $txt;
2302 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2307 sub __table_comment {
2310 if (my $code = $self->can('_table_comment')) {
2311 return $self->_filter_comment($self->$code(@_));
2317 sub __column_comment {
2320 if (my $code = $self->can('_column_comment')) {
2321 return $self->_filter_comment($self->$code(@_));
2327 # Stores a POD documentation
2329 my ($self, $class, $stmt) = @_;
2330 $self->_raw_stmt( $class, "\n" . $stmt );
2334 my ($self, $class ) = @_;
2335 $self->_raw_stmt( $class, "\n=cut\n" );
2338 # Store a raw source line for a class (for dumping purposes)
2340 my ($self, $class, $stmt) = @_;
2341 push(@{$self->{_dump_storage}->{$class}}, $stmt);
2344 # Like above, but separately for the externally loaded stuff
2346 my ($self, $class, $stmt) = @_;
2347 push(@{$self->{_ext_storage}->{$class}}, $stmt);
2350 sub _custom_column_info {
2351 my ( $self, $table_name, $column_name, $column_info ) = @_;
2353 if (my $code = $self->custom_column_info) {
2354 return $code->($table_name, $column_name, $column_info) || {};
2359 sub _datetime_column_info {
2360 my ( $self, $table_name, $column_name, $column_info ) = @_;
2362 my $type = $column_info->{data_type} || '';
2363 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2364 or ($type =~ /date|timestamp/i)) {
2365 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2366 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
2372 my ($self, $name) = @_;
2374 return $self->preserve_case ? $name : lc($name);
2378 my ($self, $name) = @_;
2380 return $self->preserve_case ? $name : uc($name);
2383 sub _unregister_source_for_table {
2384 my ($self, $table) = @_;
2388 my $schema = $self->schema;
2389 # in older DBIC it's a private method
2390 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2391 $schema->$unregister($self->_table2moniker($table));
2392 delete $self->monikers->{$table};
2393 delete $self->classes->{$table};
2394 delete $self->_upgrading_classes->{$table};
2395 delete $self->{_tables}{$table};
2399 # remove the dump dir from @INC on destruction
2403 @INC = grep $_ ne $self->dump_directory, @INC;
2408 Returns a hashref of loaded table to moniker mappings. There will
2409 be two entries for each table, the original name and the "normalized"
2410 name, in the case that the two are different (such as databases
2411 that like uppercase table names, or preserve your original mixed-case
2412 definitions, or what-have-you).
2416 Returns a hashref of table to class mappings. In some cases it will
2417 contain multiple entries per table for the original and normalized table
2418 names, as above in L</monikers>.
2420 =head1 COLUMN ACCESSOR COLLISIONS
2422 Occasionally you may have a column name that collides with a perl method, such
2423 as C<can>. In such cases, the default action is to set the C<accessor> of the
2424 column spec to C<undef>.
2426 You can then name the accessor yourself by placing code such as the following
2429 __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2431 Another option is to use the L</col_collision_map> option.
2433 =head1 RELATIONSHIP NAME COLLISIONS
2435 In very rare cases, you may get a collision between a generated relationship
2436 name and a method in your Result class, for example if you have a foreign key
2437 called C<belongs_to>.
2439 This is a problem because relationship names are also relationship accessor
2440 methods in L<DBIx::Class>.
2442 The default behavior is to append C<_rel> to the relationship name and print
2443 out a warning that refers to this text.
2445 You can also control the renaming with the L</rel_collision_map> option.
2449 L<DBIx::Class::Schema::Loader>
2453 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2457 This library is free software; you can redistribute it and/or modify it under
2458 the same terms as Perl itself.
2463 # vim:et sts=4 sw=4 tw=0: