1 package DBIx::Class::Schema::Loader::Base;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
8 use Carp::Clan qw/^DBIx::Class/;
9 use DBIx::Class::Schema::Loader::RelBuilder ();
10 use Data::Dump 'dump';
15 use Lingua::EN::Inflect::Number ();
16 use Lingua::EN::Inflect::Phrase ();
17 use String::ToIdentifier::EN ();
18 use String::ToIdentifier::EN::Unicode ();
21 use Class::Inspector ();
22 use Scalar::Util 'looks_like_number';
23 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_package_without_redefine_warnings class_path slurp_file/;
24 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
27 use Encode qw/encode decode/;
28 use List::MoreUtils qw/all any firstidx uniq/;
29 use File::Temp 'tempfile';
32 our $VERSION = '0.07036';
34 __PACKAGE__->mk_group_ro_accessors('simple', qw/
41 additional_base_classes
57 default_resultset_class
63 overwrite_modifications
86 __PACKAGE__->mk_group_accessors('simple', qw/
88 schema_version_to_dump
90 _upgrading_from_load_classes
91 _downgrading_to_load_classes
92 _rewriting_result_namespace
97 pod_comment_spillover_length
103 result_components_map
105 datetime_undef_if_invalid
106 _result_class_methods
108 filter_generated_code
112 moniker_part_separator
115 my $CURRENT_V = 'v7';
118 schema_components schema_base_class result_base_class
119 additional_base_classes left_base_classes additional_classes components
125 my $CRLF = "\x0d\x0a";
129 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
133 See L<DBIx::Class::Schema::Loader>.
137 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
138 classes, and implements the common functionality between them.
140 =head1 CONSTRUCTOR OPTIONS
142 These constructor options are the base options for
143 L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
145 =head2 skip_relationships
147 Skip setting up relationships. The default is to attempt the loading
150 =head2 skip_load_external
152 Skip loading of other classes in @INC. The default is to merge all other classes
153 with the same name found in @INC into the schema file we are creating.
157 Static schemas (ones dumped to disk) will, by default, use the new-style
158 relationship names and singularized Results, unless you're overwriting an
159 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
160 which case the backward compatible RelBuilder will be activated, and the
161 appropriate monikerization used.
167 will disable the backward-compatible RelBuilder and use
168 the new-style relationship names along with singularized Results, even when
169 overwriting a dump made with an earlier version.
171 The option also takes a hashref:
174 relationships => 'v8',
176 column_accessors => 'v8',
182 naming => { ALL => 'v8', force_ascii => 1 }
190 Set L</relationships>, L</monikers> and L</column_accessors> to the specified
195 How to name relationship accessors.
199 How to name Result classes.
201 =item column_accessors
203 How to name column accessors in Result classes.
207 For L</v8> mode and later, uses L<String::ToIdentifier::EN> instead of
208 L<String::ToIdentifier::EM::Unicode> to force monikers and other identifiers to
219 Latest style, whatever that happens to be.
223 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
227 Monikers singularized as whole words, C<might_have> relationships for FKs on
228 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
230 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
235 All monikers and relationships are inflected using
236 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
237 from relationship names.
239 In general, there is very little difference between v5 and v6 schemas.
243 This mode is identical to C<v6> mode, except that monikerization of CamelCase
244 table names is also done better (but best in v8.)
246 CamelCase column names in case-preserving mode will also be handled better
247 for relationship name inflection (but best in v8.) See L</preserve_case>.
249 In this mode, CamelCase L</column_accessors> are normalized based on case
250 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
256 The default mode is L</v7>, to get L</v8> mode, you have to specify it in
257 L</naming> explicitly until C<0.08> comes out.
259 L</monikers> and L</column_accessors> are created using
260 L<String::ToIdentifier::EN::Unicode> or L<String::ToIdentifier::EN> if
261 L</force_ascii> is set; this is only significant for names with non-C<\w>
262 characters such as C<.>.
264 CamelCase identifiers with words in all caps, e.g. C<VLANValidID> are supported
265 correctly in this mode.
267 For relationships, belongs_to accessors are made from column names by stripping
268 postfixes other than C<_id> as well, for example just C<Id>, C<_?ref>, C<_?cd>,
269 C<_?code> and C<_?num>, case insensitively.
273 For L</monikers>, this option does not inflect the table names but makes
274 monikers based on the actual name. For L</column_accessors> this option does
275 not normalize CamelCase column names to lowercase column accessors, but makes
276 accessors that are the same names as the columns (with any non-\w chars
277 replaced with underscores.)
281 For L</monikers>, singularizes the names using the most current inflector. This
282 is the same as setting the option to L</current>.
286 For L</monikers>, pluralizes the names, using the most current inflector.
290 Dynamic schemas will always default to the 0.04XXX relationship names and won't
291 singularize Results for backward compatibility, to activate the new RelBuilder
292 and singularization put this in your C<Schema.pm> file:
294 __PACKAGE__->naming('current');
296 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
297 next major version upgrade:
299 __PACKAGE__->naming('v7');
303 If true, will not print the usual C<Dumping manual schema ... Schema dump
304 completed.> messages. Does not affect warnings (except for warnings related to
305 L</really_erase_my_files>.)
309 By default POD will be generated for columns and relationships, using database
310 metadata for the text if available and supported.
312 Comment metadata can be stored in two ways.
314 The first is that you can create two tables named C<table_comments> and
315 C<column_comments> respectively. These tables must exist in the same database
316 and schema as the tables they describe. They both need to have columns named
317 C<table_name> and C<comment_text>. The second one needs to have a column named
318 C<column_name>. Then data stored in these tables will be used as a source of
319 metadata about tables and comments.
321 (If you wish you can change the name of these tables with the parameters
322 L</table_comments_table> and L</column_comments_table>.)
324 As a fallback you can use built-in commenting mechanisms. Currently this is
325 only supported for PostgreSQL, Oracle and MySQL. To create comments in
326 PostgreSQL you add statements of the form C<COMMENT ON TABLE some_table IS
327 '...'>, the same syntax is used in Oracle. To create comments in MySQL you add
328 C<COMMENT '...'> to the end of the column or table definition. Note that MySQL
329 restricts the length of comments, and also does not handle complex Unicode
332 Set this to C<0> to turn off all POD generation.
334 =head2 pod_comment_mode
336 Controls where table comments appear in the generated POD. Smaller table
337 comments are appended to the C<NAME> section of the documentation, and larger
338 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
339 section to be generated with the comment always, only use C<NAME>, or choose
340 the length threshold at which the comment is forced into the description.
346 Use C<NAME> section only.
350 Force C<DESCRIPTION> always.
354 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
359 =head2 pod_comment_spillover_length
361 When pod_comment_mode is set to C<auto>, this is the length of the comment at
362 which it will be forced into a separate description section.
366 =head2 table_comments_table
368 The table to look for comments about tables in. By default C<table_comments>.
369 See L</generate_pod> for details.
371 This must not be a fully qualified name, the table will be looked for in the
372 same database and schema as the table whose comment is being retrieved.
374 =head2 column_comments_table
376 The table to look for comments about columns in. By default C<column_comments>.
377 See L</generate_pod> for details.
379 This must not be a fully qualified name, the table will be looked for in the
380 same database and schema as the table/column whose comment is being retrieved.
382 =head2 relationship_attrs
384 Hashref of attributes to pass to each generated relationship, listed by type.
385 Also supports relationship type 'all', containing options to pass to all
386 generated relationships. Attributes set for more specific relationship types
387 override those set in 'all', and any attributes specified by this option
388 override the introspected attributes of the foreign key if any.
392 relationship_attrs => {
393 has_many => { cascade_delete => 1, cascade_copy => 1 },
394 might_have => { cascade_delete => 1, cascade_copy => 1 },
397 use this to turn L<DBIx::Class> cascades to on on your
398 L<has_many|DBIx::Class::Relationship/has_many> and
399 L<might_have|DBIx::Class::Relationship/might_have> relationships, they default
402 Can also be a coderef, for more precise control, in which case the coderef gets
403 this hash of parameters (as a list:)
405 rel_name # the name of the relationship
406 rel_type # the type of the relationship: 'belongs_to', 'has_many' or 'might_have'
407 local_source # the DBIx::Class::ResultSource object for the source the rel is *from*
408 remote_source # the DBIx::Class::ResultSource object for the source the rel is *to*
409 local_table # a DBIx::Class::Schema::Loader::Table object for the table of the source the rel is from
410 local_cols # an arrayref of column names of columns used in the rel in the source it is from
411 remote_table # a DBIx::Class::Schema::Loader::Table object for the table of the source the rel is to
412 remote_cols # an arrayref of column names of columns used in the rel in the source it is to
413 attrs # the attributes that would be set
415 it should return the new hashref of attributes, or nothing for no changes.
419 relationship_attrs => sub {
422 say "the relationship name is: $p{rel_name}";
423 say "the relationship is a: $p{rel_type}";
424 say "the local class is: ", $p{local_source}->result_class;
425 say "the remote class is: ", $p{remote_source}->result_class;
426 say "the local table is: ", $p{local_table}->sql_name;
427 say "the rel columns in the local table are: ", (join ", ", @{$p{local_cols}});
428 say "the remote table is: ", $p{remote_table}->sql_name;
429 say "the rel columns in the remote table are: ", (join ", ", @{$p{remote_cols}});
431 if ($p{local_table} eq 'dogs' && @{$p{local_cols}} == 1 && $p{local_cols}[0] eq 'name') {
432 $p{attrs}{could_be_snoopy} = 1;
438 These are the default attributes:
449 on_delete => 'CASCADE',
450 on_update => 'CASCADE',
454 For L<belongs_to|DBIx::Class::Relationship/belongs_to> relationships, these
455 defaults are overridden by the attributes introspected from the foreign key in
456 the database, if this information is available (and the driver is capable of
459 This information overrides the defaults mentioned above, and is then itself
460 overridden by the user's L</relationship_attrs> for C<belongs_to> if any are
463 In general, for most databases, for a plain foreign key with no rules, the
464 values for a L<belongs_to|DBIx::Class::Relationship/belongs_to> relationship
467 on_delete => 'NO ACTION',
468 on_update => 'NO ACTION',
471 In the cases where an attribute is not supported by the DB, a value matching
472 the actual behavior is used, for example Oracle does not support C<ON UPDATE>
473 rules, so C<on_update> is set to C<NO ACTION>. This is done so that the
474 behavior of the schema is preserved when cross deploying to a different RDBMS
475 such as SQLite for testing.
477 In the cases where the DB does not support C<DEFERRABLE> foreign keys, the
478 value is set to C<1> if L<DBIx::Class> has a working C<<
479 $storage->with_deferred_fk_checks >>. This is done so that the same
480 L<DBIx::Class> code can be used, and cross deployed from and to such databases.
484 If set to true, each constructive L<DBIx::Class> statement the loader
485 decides to execute will be C<warn>-ed before execution.
489 Set the name of the schema to load (schema in the sense that your database
492 Can be set to an arrayref of schema names for multiple schemas, or the special
493 value C<%> for all schemas.
495 For MSSQL, Sybase ASE, and Informix can be set to a hashref of databases as
496 keys and arrays of owners as values, set to the value:
500 for all owners in all databases.
502 Name clashes resulting from the same table name in different databases/schemas
503 will be resolved automatically by prefixing the moniker with the database
506 To prefix/suffix all monikers with the database and/or schema, see
511 The database table names are represented by the
512 L<DBIx::Class::Schema::Loader::Table> class in the loader, the
513 L<DBIx::Class::Schema::Loader::Table::Sybase> class for Sybase ASE and
514 L<DBIx::Class::Schema::Loader::Table::Informix> for Informix.
516 Monikers are created normally based on just the
517 L<name|DBIx::Class::Schema::Loader::DBObject/name> property, corresponding to
518 the table name, but can consist of other parts of the fully qualified name of
521 The L</moniker_parts> option is an arrayref of methods on the table class
522 corresponding to parts of the fully qualified table name, defaulting to
523 C<['name']>, in the order those parts are used to create the moniker name.
524 The parts are joined together using L</moniker_part_separator>.
526 The C<'name'> entry B<must> be present.
528 Below is a table of supported databases and possible L</moniker_parts>.
532 =item * DB2, Firebird, mysql, Oracle, Pg, SQLAnywhere, SQLite, MS Access
536 =item * Informix, MSSQL, Sybase ASE
538 C<database>, C<schema>, C<name>
542 =head2 moniker_part_separator
544 String used to join L</moniker_parts> when creating the moniker.
545 Defaults to the empty string. Use C<::> to get a separate namespace per
546 database and/or schema.
550 Only load tables matching regex. Best specified as a qr// regex.
554 Exclude tables matching regex. Best specified as a qr// regex.
558 Overrides the default table name to moniker translation. Either
564 a nested hashref, which will be traversed according to L</moniker_parts>
568 moniker_parts => [qw(schema name)],
575 In which case the table C<bar> in the C<foo> schema would get the moniker
580 a hashref of unqualified table name keys and moniker values
584 a coderef for a translator function taking a L<table
585 object|DBIx::Class::Schema::Loader::Table> argument (which stringifies to the
586 unqualified table name) and returning a scalar moniker
590 If the hash entry does not exist, or the function returns a false
591 value, the code falls back to default behavior for that table name.
593 The default behavior is to split on case transition and non-alphanumeric
594 boundaries, singularize the resulting phrase, then join the titlecased words
597 Table Name | Moniker Name
598 ---------------------------------
600 luser_group | LuserGroup
601 luser-opts | LuserOpt
602 stations_visited | StationVisited
603 routeChange | RouteChange
605 =head2 col_accessor_map
607 Same as moniker_map, but for column accessor names. If a coderef is
608 passed, the code is called with arguments of
610 the name of the column in the underlying database,
611 default accessor name that DBICSL would ordinarily give this column,
613 table_class => name of the DBIC class we are building,
614 table_moniker => calculated moniker for this table (after moniker_map if present),
615 table => table object of interface DBIx::Class::Schema::Loader::Table,
616 full_table_name => schema-qualified name of the database table (RDBMS specific),
617 schema_class => name of the schema class we are building,
618 column_info => hashref of column info (data_type, is_nullable, etc),
621 the L<table object|DBIx::Class::Schema::Loader::Table> stringifies to the
622 unqualified table name.
626 Similar in idea to moniker_map, but different in the details. It can be
627 a hashref or a code ref.
629 If it is a hashref, keys can be either the default relationship name, or the
630 moniker. The keys that are the default relationship name should map to the
631 name you want to change the relationship to. Keys that are monikers should map
632 to hashes mapping relationship names to their translation. You can do both at
633 once, and the more specific moniker version will be picked up first. So, for
634 instance, you could have
643 and relationships that would have been named C<bar> will now be named C<baz>
644 except that in the table whose moniker is C<Foo> it will be named C<blat>.
646 If it is a coderef, the argument passed will be a hashref of this form:
649 name => default relationship name,
650 type => the relationship type eg: C<has_many>,
651 local_class => name of the DBIC class we are building,
652 local_moniker => moniker of the DBIC class we are building,
653 local_columns => columns in this table in the relationship,
654 remote_class => name of the DBIC class we are related to,
655 remote_moniker => moniker of the DBIC class we are related to,
656 remote_columns => columns in the other table in the relationship,
657 # for type => "many_to_many" only:
658 link_class => name of the DBIC class for the link table
659 link_moniker => moniker of the DBIC class for the link table
660 link_rel_name => name of the relationship to the link table
663 DBICSL will try to use the value returned as the relationship name.
665 =head2 inflect_plural
667 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
668 if hash key does not exist or coderef returns false), but acts as a map
669 for pluralizing relationship names. The default behavior is to utilize
670 L<Lingua::EN::Inflect::Phrase/to_PL>.
672 =head2 inflect_singular
674 As L</inflect_plural> above, but for singularizing relationship names.
675 Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
677 =head2 schema_base_class
679 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
681 =head2 schema_components
683 List of components to load into the Schema class.
685 =head2 result_base_class
687 Base class for your table classes (aka result classes). Defaults to
690 =head2 additional_base_classes
692 List of additional base classes all of your table classes will use.
694 =head2 left_base_classes
696 List of additional base classes all of your table classes will use
697 that need to be leftmost.
699 =head2 additional_classes
701 List of additional classes which all of your table classes will use.
705 List of additional components to be loaded into all of your Result
706 classes. A good example would be
707 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
709 =head2 result_components_map
711 A hashref of moniker keys and component values. Unlike L</components>, which
712 loads the given components into every Result class, this option allows you to
713 load certain components for specified Result classes. For example:
715 result_components_map => {
716 StationVisited => '+YourApp::Schema::Component::StationVisited',
718 '+YourApp::Schema::Component::RouteChange',
719 'InflateColumn::DateTime',
723 You may use this in conjunction with L</components>.
727 List of L<Moose> roles to be applied to all of your Result classes.
729 =head2 result_roles_map
731 A hashref of moniker keys and role values. Unlike L</result_roles>, which
732 applies the given roles to every Result class, this option allows you to apply
733 certain roles for specified Result classes. For example:
735 result_roles_map => {
737 'YourApp::Role::Building',
738 'YourApp::Role::Destination',
740 RouteChange => 'YourApp::Role::TripEvent',
743 You may use this in conjunction with L</result_roles>.
745 =head2 use_namespaces
747 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
750 Generate result class names suitable for
751 L<DBIx::Class::Schema/load_namespaces> and call that instead of
752 L<DBIx::Class::Schema/load_classes>. When using this option you can also
753 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
754 C<resultset_namespace>, C<default_resultset_class>), and they will be added
755 to the call (and the generated result class names adjusted appropriately).
757 =head2 dump_directory
759 The value of this option is a perl libdir pathname. Within
760 that directory this module will create a baseline manual
761 L<DBIx::Class::Schema> module set, based on what it creates at runtime.
763 The created schema class will have the same classname as the one on
764 which you are setting this option (and the ResultSource classes will be
765 based on this name as well).
767 Normally you wouldn't hard-code this setting in your schema class, as it
768 is meant for one-time manual usage.
770 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
771 recommended way to access this functionality.
773 =head2 dump_overwrite
775 Deprecated. See L</really_erase_my_files> below, which does *not* mean
776 the same thing as the old C<dump_overwrite> setting from previous releases.
778 =head2 really_erase_my_files
780 Default false. If true, Loader will unconditionally delete any existing
781 files before creating the new ones from scratch when dumping a schema to disk.
783 The default behavior is instead to only replace the top portion of the
784 file, up to and including the final stanza which contains
785 C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
786 leaving any customizations you placed after that as they were.
788 When C<really_erase_my_files> is not set, if the output file already exists,
789 but the aforementioned final stanza is not found, or the checksum
790 contained there does not match the generated contents, Loader will
791 croak and not touch the file.
793 You should really be using version control on your schema classes (and all
794 of the rest of your code for that matter). Don't blame me if a bug in this
795 code wipes something out when it shouldn't have, you've been warned.
797 =head2 overwrite_modifications
799 Default false. If false, when updating existing files, Loader will
800 refuse to modify any Loader-generated code that has been modified
801 since its last run (as determined by the checksum Loader put in its
804 If true, Loader will discard any manual modifications that have been
805 made to Loader-generated code.
807 Again, you should be using version control on your schema classes. Be
808 careful with this option.
810 =head2 custom_column_info
812 Hook for adding extra attributes to the
813 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
815 Must be a coderef that returns a hashref with the extra attributes.
817 Receives the L<table object|DBIx::Class::Schema::Loader::Table> (which
818 stringifies to the unqualified table name), column name and column_info.
822 custom_column_info => sub {
823 my ($table, $column_name, $column_info) = @_;
825 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
826 return { is_snoopy => 1 };
830 This attribute can also be used to set C<inflate_datetime> on a non-datetime
831 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
833 =head2 datetime_timezone
835 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
836 columns with the DATE/DATETIME/TIMESTAMP data_types.
838 =head2 datetime_locale
840 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
841 columns with the DATE/DATETIME/TIMESTAMP data_types.
843 =head2 datetime_undef_if_invalid
845 Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
846 datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
849 The default is recommended to deal with data such as C<00/00/00> which
850 sometimes ends up in such columns in MySQL.
854 File in Perl format, which should return a HASH reference, from which to read
859 Normally database names are lowercased and split by underscore, use this option
860 if you have CamelCase database names.
862 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
863 case-sensitive collation will turn this option on unconditionally.
865 B<NOTE:> L</naming> = C<v8> is highly recommended with this option as the
866 semantics of this mode are much improved for CamelCase database names.
868 L</naming> = C<v7> or greater is required with this option.
870 =head2 qualify_objects
872 Set to true to prepend the L</db_schema> to table names for C<<
873 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
875 This attribute is automatically set to true for multi db_schema configurations,
876 unless explicitly set to false by the user.
880 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
881 L<MooseX::MarkAsMethods> (or L<namespace::autoclean>, see below). The default
882 content after the md5 sum also makes the classes immutable.
884 It is safe to upgrade your existing Schema to this option.
886 =head2 only_autoclean
888 By default, we use L<MooseX::MarkAsMethods> to remove imported functions from
889 your generated classes. It uses L<namespace::autoclean> to do this, after
890 telling your object's metaclass that any operator L<overload>s in your class
891 are methods, which will cause namespace::autoclean to spare them from removal.
893 This prevents the "Hey, where'd my overloads go?!" effect.
895 If you don't care about operator overloads, enabling this option falls back to
896 just using L<namespace::autoclean> itself.
898 If none of the above made any sense, or you don't have some pressing need to
899 only use L<namespace::autoclean>, leaving this set to the default is
902 =head2 col_collision_map
904 This option controls how accessors for column names which collide with perl
905 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
907 This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
908 strings which are compiled to regular expressions that map to
909 L<sprintf|perlfunc/sprintf> formats.
913 col_collision_map => 'column_%s'
915 col_collision_map => { '(.*)' => 'column_%s' }
917 col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
919 =head2 rel_collision_map
921 Works just like L</col_collision_map>, but for relationship names/accessors
922 rather than column names/accessors.
924 The default is to just append C<_rel> to the relationship name, see
925 L</RELATIONSHIP NAME COLLISIONS>.
927 =head2 uniq_to_primary
929 Automatically promotes the largest unique constraints with non-nullable columns
930 on tables to primary keys, assuming there is only one largest unique
933 =head2 filter_generated_code
935 An optional hook that lets you filter the generated text for various classes
936 through a function that change it in any way that you want. The function will
937 receive the type of file, C<schema> or C<result>, class and code; and returns
938 the new code to use instead. For instance you could add custom comments, or do
939 anything else that you want.
941 The option can also be set to a string, which is then used as a filter program,
944 If this exists but fails to return text matching C</\bpackage\b/>, no file will
947 filter_generated_code => sub {
948 my ($type, $class, $text) = @_;
955 None of these methods are intended for direct invocation by regular
956 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
957 L<DBIx::Class::Schema::Loader>.
961 # ensure that a piece of object data is a valid arrayref, creating
962 # an empty one or encapsulating whatever's there.
963 sub _ensure_arrayref {
968 $self->{$_} = [ $self->{$_} ]
969 unless ref $self->{$_} eq 'ARRAY';
975 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
976 by L<DBIx::Class::Schema::Loader>.
981 my ( $class, %args ) = @_;
983 if (exists $args{column_accessor_map}) {
984 $args{col_accessor_map} = delete $args{column_accessor_map};
987 my $self = { %args };
989 # don't lose undef options
990 for (values %$self) {
991 $_ = 0 unless defined $_;
994 bless $self => $class;
996 if (my $config_file = $self->config_file) {
997 my $config_opts = do $config_file;
999 croak "Error reading config from $config_file: $@" if $@;
1001 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
1003 while (my ($k, $v) = each %$config_opts) {
1004 $self->{$k} = $v unless exists $self->{$k};
1008 if (defined $self->{result_component_map}) {
1009 if (defined $self->result_components_map) {
1010 croak "Specify only one of result_components_map or result_component_map";
1012 $self->result_components_map($self->{result_component_map})
1015 if (defined $self->{result_role_map}) {
1016 if (defined $self->result_roles_map) {
1017 croak "Specify only one of result_roles_map or result_role_map";
1019 $self->result_roles_map($self->{result_role_map})
1022 croak "the result_roles and result_roles_map options may only be used in conjunction with use_moose=1"
1023 if ((not defined $self->use_moose) || (not $self->use_moose))
1024 && ((defined $self->result_roles) || (defined $self->result_roles_map));
1026 $self->_ensure_arrayref(qw/schema_components
1028 additional_base_classes
1034 $self->_validate_class_args;
1036 croak "result_components_map must be a hash"
1037 if defined $self->result_components_map
1038 && ref $self->result_components_map ne 'HASH';
1040 if ($self->result_components_map) {
1041 my %rc_map = %{ $self->result_components_map };
1042 foreach my $moniker (keys %rc_map) {
1043 $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
1045 $self->result_components_map(\%rc_map);
1048 $self->result_components_map({});
1050 $self->_validate_result_components_map;
1052 croak "result_roles_map must be a hash"
1053 if defined $self->result_roles_map
1054 && ref $self->result_roles_map ne 'HASH';
1056 if ($self->result_roles_map) {
1057 my %rr_map = %{ $self->result_roles_map };
1058 foreach my $moniker (keys %rr_map) {
1059 $rr_map{$moniker} = [ $rr_map{$moniker} ] unless ref $rr_map{$moniker};
1061 $self->result_roles_map(\%rr_map);
1063 $self->result_roles_map({});
1065 $self->_validate_result_roles_map;
1067 if ($self->use_moose) {
1068 if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
1069 die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
1070 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
1074 $self->{_tables} = {};
1075 $self->{monikers} = {};
1076 $self->{moniker_to_table} = {};
1077 $self->{class_to_table} = {};
1078 $self->{classes} = {};
1079 $self->{_upgrading_classes} = {};
1081 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
1082 $self->{schema} ||= $self->{schema_class};
1083 $self->{table_comments_table} ||= 'table_comments';
1084 $self->{column_comments_table} ||= 'column_comments';
1086 croak "dump_overwrite is deprecated. Please read the"
1087 . " DBIx::Class::Schema::Loader::Base documentation"
1088 if $self->{dump_overwrite};
1090 $self->{dynamic} = ! $self->{dump_directory};
1091 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
1096 $self->{dump_directory} ||= $self->{temp_directory};
1098 $self->real_dump_directory($self->{dump_directory});
1100 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1101 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1103 if (not defined $self->naming) {
1104 $self->naming_set(0);
1107 $self->naming_set(1);
1110 if ((not ref $self->naming) && defined $self->naming) {
1111 my $naming_ver = $self->naming;
1113 relationships => $naming_ver,
1114 monikers => $naming_ver,
1115 column_accessors => $naming_ver,
1118 elsif (ref $self->naming eq 'HASH' && exists $self->naming->{ALL}) {
1119 my $val = delete $self->naming->{ALL};
1121 $self->naming->{$_} = $val
1122 foreach qw/relationships monikers column_accessors/;
1125 if ($self->naming) {
1126 foreach my $key (qw/relationships monikers column_accessors/) {
1127 $self->naming->{$key} = $CURRENT_V if ($self->naming->{$key}||'') eq 'current';
1130 $self->{naming} ||= {};
1132 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
1133 croak 'custom_column_info must be a CODE ref';
1136 $self->_check_back_compat;
1138 $self->use_namespaces(1) unless defined $self->use_namespaces;
1139 $self->generate_pod(1) unless defined $self->generate_pod;
1140 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
1141 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
1143 if (my $col_collision_map = $self->col_collision_map) {
1144 if (my $reftype = ref $col_collision_map) {
1145 if ($reftype ne 'HASH') {
1146 croak "Invalid type $reftype for option 'col_collision_map'";
1150 $self->col_collision_map({ '(.*)' => $col_collision_map });
1154 if (my $rel_collision_map = $self->rel_collision_map) {
1155 if (my $reftype = ref $rel_collision_map) {
1156 if ($reftype ne 'HASH') {
1157 croak "Invalid type $reftype for option 'rel_collision_map'";
1161 $self->rel_collision_map({ '(.*)' => $rel_collision_map });
1165 if (defined(my $rel_name_map = $self->rel_name_map)) {
1166 my $reftype = ref $rel_name_map;
1167 if ($reftype ne 'HASH' && $reftype ne 'CODE') {
1168 croak "Invalid type $reftype for option 'rel_name_map', must be HASH or CODE";
1172 if (defined(my $filter = $self->filter_generated_code)) {
1173 my $reftype = ref $filter;
1174 if ($reftype && $reftype ne 'CODE') {
1175 croak "Invalid type $reftype for option 'filter_generated_code, must be a scalar or a CODE reference";
1179 if (defined $self->db_schema) {
1180 if (ref $self->db_schema eq 'ARRAY') {
1181 if (@{ $self->db_schema } > 1 && not defined $self->{qualify_objects}) {
1182 $self->{qualify_objects} = 1;
1184 elsif (@{ $self->db_schema } == 0) {
1185 $self->{db_schema} = undef;
1188 elsif (not ref $self->db_schema) {
1189 if ($self->db_schema eq '%' && not defined $self->{qualify_objects}) {
1190 $self->{qualify_objects} = 1;
1193 $self->{db_schema} = [ $self->db_schema ];
1197 if (not $self->moniker_parts) {
1198 $self->moniker_parts(['name']);
1201 if (not ref $self->moniker_parts) {
1202 $self->moniker_parts([ $self->moniker_parts ]);
1204 if (ref $self->moniker_parts ne 'ARRAY') {
1205 croak 'moniker_parts must be an arrayref';
1207 if ((firstidx { $_ eq 'name' } @{ $self->moniker_parts }) == -1) {
1208 croak "moniker_parts option *must* contain 'name'";
1212 if (not defined $self->moniker_part_separator) {
1213 $self->moniker_part_separator('');
1219 sub _check_back_compat {
1222 # dynamic schemas will always be in 0.04006 mode, unless overridden
1223 if ($self->dynamic) {
1224 # just in case, though no one is likely to dump a dynamic schema
1225 $self->schema_version_to_dump('0.04006');
1227 if (not $self->naming_set) {
1228 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1230 Dynamic schema detected, will run in 0.04006 mode.
1232 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
1233 to disable this warning.
1235 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
1240 $self->_upgrading_from('v4');
1243 if ((not defined $self->use_namespaces) && ($self->naming_set)) {
1244 $self->use_namespaces(1);
1247 $self->naming->{relationships} ||= 'v4';
1248 $self->naming->{monikers} ||= 'v4';
1250 if ($self->use_namespaces) {
1251 $self->_upgrading_from_load_classes(1);
1254 $self->use_namespaces(0);
1260 # otherwise check if we need backcompat mode for a static schema
1261 my $filename = $self->get_dump_filename($self->schema_class);
1262 return unless -e $filename;
1264 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
1265 $self->_parse_generated_file($filename);
1267 return unless $old_ver;
1269 # determine if the existing schema was dumped with use_moose => 1
1270 if (! defined $self->use_moose) {
1271 $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
1274 my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
1276 my $result_namespace = do { ($old_gen =~ /result_namespace => (.+)/) ? $1 : '' };
1277 my $ds = eval $result_namespace;
1279 Could not eval expression '$result_namespace' for result_namespace from
1282 $result_namespace = $ds || '';
1284 if ($load_classes && (not defined $self->use_namespaces)) {
1285 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1287 'load_classes;' static schema detected, turning off 'use_namespaces'.
1289 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
1290 variable to disable this warning.
1292 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
1295 $self->use_namespaces(0);
1297 elsif ($load_classes && $self->use_namespaces) {
1298 $self->_upgrading_from_load_classes(1);
1300 elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
1301 $self->_downgrading_to_load_classes(
1302 $result_namespace || 'Result'
1305 elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
1306 if (not $self->result_namespace) {
1307 $self->result_namespace($result_namespace || 'Result');
1309 elsif ($result_namespace ne $self->result_namespace) {
1310 $self->_rewriting_result_namespace(
1311 $result_namespace || 'Result'
1316 # XXX when we go past .0 this will need fixing
1317 my ($v) = $old_ver =~ /([1-9])/;
1320 return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
1322 if (not %{ $self->naming }) {
1323 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
1325 Version $old_ver static schema detected, turning on backcompat mode.
1327 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
1328 to disable this warning.
1330 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
1332 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
1333 from version 0.04006.
1336 $self->naming->{relationships} ||= $v;
1337 $self->naming->{monikers} ||= $v;
1338 $self->naming->{column_accessors} ||= $v;
1340 $self->schema_version_to_dump($old_ver);
1343 $self->_upgrading_from($v);
1347 sub _validate_class_args {
1350 foreach my $k (@CLASS_ARGS) {
1351 next unless $self->$k;
1353 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
1354 $self->_validate_classes($k, \@classes);
1358 sub _validate_result_components_map {
1361 foreach my $classes (values %{ $self->result_components_map }) {
1362 $self->_validate_classes('result_components_map', $classes);
1366 sub _validate_result_roles_map {
1369 foreach my $classes (values %{ $self->result_roles_map }) {
1370 $self->_validate_classes('result_roles_map', $classes);
1374 sub _validate_classes {
1377 my $classes = shift;
1379 # make a copy to not destroy original
1380 my @classes = @$classes;
1382 foreach my $c (@classes) {
1383 # components default to being under the DBIx::Class namespace unless they
1384 # are preceded with a '+'
1385 if ( $key =~ m/component/ && $c !~ s/^\+// ) {
1386 $c = 'DBIx::Class::' . $c;
1389 # 1 == installed, 0 == not installed, undef == invalid classname
1390 my $installed = Class::Inspector->installed($c);
1391 if ( defined($installed) ) {
1392 if ( $installed == 0 ) {
1393 croak qq/$c, as specified in the loader option "$key", is not installed/;
1396 croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
1402 sub _find_file_in_inc {
1403 my ($self, $file) = @_;
1405 foreach my $prefix (@INC) {
1406 my $fullpath = File::Spec->catfile($prefix, $file);
1407 return $fullpath if -f $fullpath
1408 # abs_path throws on Windows for nonexistent files
1409 and (try { Cwd::abs_path($fullpath) }) ne
1410 ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
1416 sub _find_class_in_inc {
1417 my ($self, $class) = @_;
1419 return $self->_find_file_in_inc(class_path($class));
1425 return $self->_upgrading_from
1426 || $self->_upgrading_from_load_classes
1427 || $self->_downgrading_to_load_classes
1428 || $self->_rewriting_result_namespace
1432 sub _rewrite_old_classnames {
1433 my ($self, $code) = @_;
1435 return $code unless $self->_rewriting;
1437 my %old_classes = reverse %{ $self->_upgrading_classes };
1439 my $re = join '|', keys %old_classes;
1440 $re = qr/\b($re)\b/;
1442 $code =~ s/$re/$old_classes{$1} || $1/eg;
1447 sub _load_external {
1448 my ($self, $class) = @_;
1450 return if $self->{skip_load_external};
1452 # so that we don't load our own classes, under any circumstances
1453 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
1455 my $real_inc_path = $self->_find_class_in_inc($class);
1457 my $old_class = $self->_upgrading_classes->{$class}
1458 if $self->_rewriting;
1460 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
1461 if $old_class && $old_class ne $class;
1463 return unless $real_inc_path || $old_real_inc_path;
1465 if ($real_inc_path) {
1466 # If we make it to here, we loaded an external definition
1467 warn qq/# Loaded external class definition for '$class'\n/
1470 my $code = $self->_rewrite_old_classnames(slurp_file $real_inc_path);
1472 if ($self->dynamic) { # load the class too
1473 eval_package_without_redefine_warnings($class, $code);
1476 $self->_ext_stmt($class,
1477 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
1478 .qq|# They are now part of the custom portion of this file\n|
1479 .qq|# for you to hand-edit. If you do not either delete\n|
1480 .qq|# this section or remove that file from \@INC, this section\n|
1481 .qq|# will be repeated redundantly when you re-create this\n|
1482 .qq|# file again via Loader! See skip_load_external to disable\n|
1483 .qq|# this feature.\n|
1486 $self->_ext_stmt($class, $code);
1487 $self->_ext_stmt($class,
1488 qq|# End of lines loaded from '$real_inc_path' |
1492 if ($old_real_inc_path) {
1493 my $code = slurp_file $old_real_inc_path;
1495 $self->_ext_stmt($class, <<"EOF");
1497 # These lines were loaded from '$old_real_inc_path',
1498 # based on the Result class name that would have been created by an older
1499 # version of the Loader. For a static schema, this happens only once during
1500 # upgrade. See skip_load_external to disable this feature.
1503 $code = $self->_rewrite_old_classnames($code);
1505 if ($self->dynamic) {
1508 Detected external content in '$old_real_inc_path', a class name that would have
1509 been used by an older version of the Loader.
1511 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
1512 new name of the Result.
1514 eval_package_without_redefine_warnings($class, $code);
1518 $self->_ext_stmt($class, $code);
1519 $self->_ext_stmt($class,
1520 qq|# End of lines loaded from '$old_real_inc_path' |
1527 Does the actual schema-construction work.
1534 $self->_load_tables(
1535 $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1543 Rescan the database for changes. Returns a list of the newly added table
1546 The schema argument should be the schema class or object to be affected. It
1547 should probably be derived from the original schema_class used during L</load>.
1552 my ($self, $schema) = @_;
1554 $self->{schema} = $schema;
1555 $self->_relbuilder->{schema} = $schema;
1558 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
1560 foreach my $table (@current) {
1561 if(!exists $self->_tables->{$table->sql_name}) {
1562 push(@created, $table);
1567 @current{map $_->sql_name, @current} = ();
1568 foreach my $table (values %{ $self->_tables }) {
1569 if (not exists $current{$table->sql_name}) {
1570 $self->_remove_table($table);
1574 delete @$self{qw/_dump_storage _relations_started _uniqs_started/};
1576 my $loaded = $self->_load_tables(@current);
1578 foreach my $table (@created) {
1579 $self->monikers->{$table->sql_name} = $self->_table2moniker($table);
1582 return map { $self->monikers->{$_->sql_name} } @created;
1588 return if $self->{skip_relationships};
1590 return $self->{relbuilder} ||= do {
1591 my $relbuilder_suff =
1598 ->{$self->naming->{relationships}||$CURRENT_V} || '';
1600 my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1601 $self->ensure_class_loaded($relbuilder_class);
1602 $relbuilder_class->new($self);
1607 my ($self, @tables) = @_;
1609 # Save the new tables to the tables list and compute monikers
1611 $self->_tables->{$_->sql_name} = $_;
1612 $self->monikers->{$_->sql_name} = $self->_table2moniker($_);
1615 # check for moniker clashes
1616 my $inverse_moniker_idx;
1617 foreach my $imtable (values %{ $self->_tables }) {
1618 push @{ $inverse_moniker_idx->{$self->monikers->{$imtable->sql_name}} }, $imtable;
1622 foreach my $moniker (keys %$inverse_moniker_idx) {
1623 my $imtables = $inverse_moniker_idx->{$moniker};
1624 if (@$imtables > 1) {
1625 my $different_databases =
1626 $imtables->[0]->can('database') && (uniq map $_->database||'', @$imtables) > 1;
1628 my $different_schemas =
1629 (uniq map $_->schema||'', @$imtables) > 1;
1631 if ($different_databases || $different_schemas) {
1632 my ($use_schema, $use_database) = (1, 0);
1634 if ($different_databases) {
1637 # If any monikers are in the same database, we have to distinguish by
1638 # both schema and database.
1640 $db_counts{$_}++ for map $_->database, @$imtables;
1641 $use_schema = any { $_ > 1 } values %db_counts;
1644 foreach my $tbl (@$imtables) { delete $self->monikers->{$tbl->sql_name}; }
1646 my $moniker_parts = [ @{ $self->moniker_parts } ];
1648 my $have_schema = any { $_ eq 'schema' } @{ $self->moniker_parts };
1649 my $have_database = any { $_ eq 'database' } @{ $self->moniker_parts };
1651 unshift @$moniker_parts, 'schema' if $use_schema && !$have_schema;
1652 unshift @$moniker_parts, 'database' if $use_database && !$have_database;
1654 local $self->{moniker_parts} = $moniker_parts;
1658 foreach my $tbl (@$imtables) { $new_monikers{$tbl->sql_name} = $self->_table2moniker($tbl); }
1659 foreach my $name (map $_->sql_name, @$imtables) { $self->monikers->{$name} = $new_monikers{$name}; }
1661 # check if there are still clashes
1664 while (my ($t, $m) = each %new_monikers) {
1665 push @{ $by_moniker{$m} }, $t;
1668 foreach my $m (grep @{ $by_moniker{$_} } > 1, keys %by_moniker) {
1669 push @clashes, sprintf ("tried disambiguating by moniker_parts, but tables %s still reduced to the same source moniker '%s'",
1670 join (', ', @{ $by_moniker{$m} }),
1676 push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1677 join (', ', map $_->sql_name, @$imtables),
1685 die 'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1686 . 'Change the naming style, or supply an explicit moniker_map: '
1687 . join ('; ', @clashes)
1692 foreach my $tbl (@tables) { $self->_make_src_class($tbl); }
1693 foreach my $tbl (@tables) { $self->_setup_src_meta($tbl); }
1695 if(!$self->skip_relationships) {
1696 # The relationship loader needs a working schema
1697 local $self->{quiet} = 1;
1698 local $self->{dump_directory} = $self->{temp_directory};
1699 $self->_reload_classes(\@tables);
1700 $self->_load_relationships(\@tables);
1702 # Remove that temp dir from INC so it doesn't get reloaded
1703 @INC = grep $_ ne $self->dump_directory, @INC;
1706 foreach my $tbl (@tables) { $self->_load_roles($tbl); }
1707 foreach my $tbl (map { $self->classes->{$_->sql_name} } @tables) { $self->_load_external($tbl); }
1709 # Reload without unloading first to preserve any symbols from external
1711 $self->_reload_classes(\@tables, { unload => 0 });
1713 # Drop temporary cache
1714 delete $self->{_cache};
1719 sub _reload_classes {
1720 my ($self, $tables, $opts) = @_;
1722 my @tables = @$tables;
1724 my $unload = $opts->{unload};
1725 $unload = 1 unless defined $unload;
1727 # so that we don't repeat custom sections
1728 @INC = grep $_ ne $self->dump_directory, @INC;
1730 $self->_dump_to_dir(map { $self->classes->{$_->sql_name} } @tables);
1732 unshift @INC, $self->dump_directory;
1735 my %have_source = map { $_ => $self->schema->source($_) }
1736 $self->schema->sources;
1738 for my $table (@tables) {
1739 my $moniker = $self->monikers->{$table->sql_name};
1740 my $class = $self->classes->{$table->sql_name};
1743 no warnings 'redefine';
1744 local *Class::C3::reinitialize = sub {}; # to speed things up, reinitialized below
1747 if (my $mc = $self->_moose_metaclass($class)) {
1750 Class::Unload->unload($class) if $unload;
1751 my ($source, $resultset_class);
1753 ($source = $have_source{$moniker})
1754 && ($resultset_class = $source->resultset_class)
1755 && ($resultset_class ne 'DBIx::Class::ResultSet')
1757 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1758 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1761 Class::Unload->unload($resultset_class) if $unload;
1762 $self->_reload_class($resultset_class) if $has_file;
1764 $self->_reload_class($class);
1766 push @to_register, [$moniker, $class];
1769 Class::C3->reinitialize;
1770 for (@to_register) {
1771 $self->schema->register_class(@$_);
1775 sub _moose_metaclass {
1776 return undef unless $INC{'Class/MOP.pm'}; # if CMOP is not loaded the class could not have loaded in the 1st place
1780 my $mc = try { Class::MOP::class_of($class) }
1783 return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1786 # We use this instead of ensure_class_loaded when there are package symbols we
1789 my ($self, $class) = @_;
1791 delete $INC{ +class_path($class) };
1794 eval_package_without_redefine_warnings ($class, "require $class");
1797 my $source = slurp_file $self->_get_dump_filename($class);
1798 die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
1802 sub _get_dump_filename {
1803 my ($self, $class) = (@_);
1805 $class =~ s{::}{/}g;
1806 return $self->dump_directory . q{/} . $class . q{.pm};
1809 =head2 get_dump_filename
1813 Returns the full path to the file for a class that the class has been or will
1814 be dumped to. This is a file in a temp dir for a dynamic schema.
1818 sub get_dump_filename {
1819 my ($self, $class) = (@_);
1821 local $self->{dump_directory} = $self->real_dump_directory;
1823 return $self->_get_dump_filename($class);
1826 sub _ensure_dump_subdirs {
1827 my ($self, $class) = (@_);
1829 my @name_parts = split(/::/, $class);
1830 pop @name_parts; # we don't care about the very last element,
1831 # which is a filename
1833 my $dir = $self->dump_directory;
1836 mkdir($dir) or croak "mkdir('$dir') failed: $!";
1838 last if !@name_parts;
1839 $dir = File::Spec->catdir($dir, shift @name_parts);
1844 my ($self, @classes) = @_;
1846 my $schema_class = $self->schema_class;
1847 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1849 my $target_dir = $self->dump_directory;
1850 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1851 unless $self->dynamic or $self->quiet;
1855 . qq|package $schema_class;\n\n|
1856 . qq|# Created by DBIx::Class::Schema::Loader\n|
1857 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1860 = $self->only_autoclean
1861 ? 'namespace::autoclean'
1862 : 'MooseX::MarkAsMethods autoclean => 1'
1865 if ($self->use_moose) {
1867 $schema_text.= qq|use Moose;\nuse $autoclean;\nextends '$schema_base_class';\n\n|;
1870 $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
1873 my @schema_components = @{ $self->schema_components || [] };
1875 if (@schema_components) {
1876 my $schema_components = dump @schema_components;
1877 $schema_components = "($schema_components)" if @schema_components == 1;
1879 $schema_text .= "__PACKAGE__->load_components${schema_components};\n\n";
1882 if ($self->use_namespaces) {
1883 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1884 my $namespace_options;
1886 my @attr = qw/resultset_namespace default_resultset_class/;
1888 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1890 for my $attr (@attr) {
1892 my $code = dumper_squashed $self->$attr;
1893 $namespace_options .= qq| $attr => $code,\n|
1896 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1897 $schema_text .= qq|;\n|;
1900 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1904 local $self->{version_to_dump} = $self->schema_version_to_dump;
1905 $self->_write_classfile($schema_class, $schema_text, 1);
1908 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1910 foreach my $src_class (@classes) {
1913 . qq|package $src_class;\n\n|
1914 . qq|# Created by DBIx::Class::Schema::Loader\n|
1915 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1917 $src_text .= $self->_make_pod_heading($src_class);
1919 $src_text .= qq|use strict;\nuse warnings;\n\n|;
1921 $src_text .= $self->_base_class_pod($result_base_class)
1922 unless $result_base_class eq 'DBIx::Class::Core';
1924 if ($self->use_moose) {
1925 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse $autoclean;|;
1927 # these options 'use base' which is compile time
1928 if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1929 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n|;
1932 $src_text .= qq|\nextends '$result_base_class';\n|;
1936 $src_text .= qq|use base '$result_base_class';\n|;
1939 $self->_write_classfile($src_class, $src_text);
1942 # remove Result dir if downgrading from use_namespaces, and there are no
1944 if (my $result_ns = $self->_downgrading_to_load_classes
1945 || $self->_rewriting_result_namespace) {
1946 my $result_namespace = $self->_result_namespace(
1951 (my $result_dir = $result_namespace) =~ s{::}{/}g;
1952 $result_dir = $self->dump_directory . '/' . $result_dir;
1954 unless (my @files = glob "$result_dir/*") {
1959 warn "Schema dump completed.\n" unless $self->dynamic or $self->quiet;
1963 my ($self, $version, $ts) = @_;
1964 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1967 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1970 sub _write_classfile {
1971 my ($self, $class, $text, $is_schema) = @_;
1973 my $filename = $self->_get_dump_filename($class);
1974 $self->_ensure_dump_subdirs($class);
1976 if (-f $filename && $self->really_erase_my_files) {
1977 warn "Deleting existing file '$filename' due to "
1978 . "'really_erase_my_files' setting\n" unless $self->quiet;
1982 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1983 = $self->_parse_generated_file($filename);
1985 if (! $old_gen && -f $filename) {
1986 croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1987 . " it does not appear to have been generated by Loader"
1990 my $custom_content = $old_custom || '';
1992 # Use custom content from a renamed class, the class names in it are
1994 if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1995 my $old_filename = $self->_get_dump_filename($renamed_class);
1997 if (-f $old_filename) {
1998 $custom_content = ($self->_parse_generated_file ($old_filename))[4];
2000 unlink $old_filename;
2004 $custom_content ||= $self->_default_custom_content($is_schema);
2006 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
2007 # If there is already custom content, which does not have the Moose content, add it.
2008 if ($self->use_moose) {
2010 my $non_moose_custom_content = do {
2011 local $self->{use_moose} = 0;
2012 $self->_default_custom_content;
2015 if ($custom_content eq $non_moose_custom_content) {
2016 $custom_content = $self->_default_custom_content($is_schema);
2018 elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
2019 $custom_content .= $self->_default_custom_content($is_schema);
2022 elsif (defined $self->use_moose && $old_gen) {
2023 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'
2024 if $old_gen =~ /use \s+ MooseX?\b/x;
2027 $custom_content = $self->_rewrite_old_classnames($custom_content);
2030 for @{$self->{_dump_storage}->{$class} || []};
2032 if ($self->filter_generated_code) {
2033 my $filter = $self->filter_generated_code;
2035 if (ref $filter eq 'CODE') {
2037 ($is_schema ? 'schema' : 'result'),
2043 my ($fh, $temp_file) = tempfile();
2045 binmode $fh, ':encoding(UTF-8)';
2049 open my $out, qq{$filter < "$temp_file"|}
2050 or croak "Could not open pipe to $filter: $!";
2052 $text = decode('UTF-8', do { local $/; <$out> });
2054 $text =~ s/$CR?$LF/\n/g;
2058 my $exit_code = $? >> 8;
2061 or croak "Could not remove temporary file '$temp_file': $!";
2063 if ($exit_code != 0) {
2064 croak "filter '$filter' exited non-zero: $exit_code";
2067 if (not $text or not $text =~ /\bpackage\b/) {
2068 warn("$class skipped due to filter") if $self->debug;
2073 # Check and see if the dump is in fact different
2077 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
2078 if (Digest::MD5::md5_base64(encode 'UTF-8', $compare_to) eq $old_md5) {
2079 return unless $self->_upgrading_from && $is_schema;
2083 $text .= $self->_sig_comment(
2084 $self->version_to_dump,
2085 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
2088 open(my $fh, '>:encoding(UTF-8)', $filename)
2089 or croak "Cannot open '$filename' for writing: $!";
2091 # Write the top half and its MD5 sum
2092 print $fh $text . Digest::MD5::md5_base64(encode 'UTF-8', $text) . "\n";
2094 # Write out anything loaded via external partial class file in @INC
2096 for @{$self->{_ext_storage}->{$class} || []};
2098 # Write out any custom content the user has added
2099 print $fh $custom_content;
2102 or croak "Error closing '$filename': $!";
2105 sub _default_moose_custom_content {
2106 my ($self, $is_schema) = @_;
2108 if (not $is_schema) {
2109 return qq|\n__PACKAGE__->meta->make_immutable;|;
2112 return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
2115 sub _default_custom_content {
2116 my ($self, $is_schema) = @_;
2117 my $default = qq|\n\n# You can replace this text with custom|
2118 . qq| code or comments, and it will be preserved on regeneration|;
2119 if ($self->use_moose) {
2120 $default .= $self->_default_moose_custom_content($is_schema);
2122 $default .= qq|\n1;\n|;
2126 sub _parse_generated_file {
2127 my ($self, $fn) = @_;
2129 return unless -f $fn;
2131 open(my $fh, '<:encoding(UTF-8)', $fn)
2132 or croak "Cannot open '$fn' for reading: $!";
2135 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\r?\n};
2137 my ($md5, $ts, $ver, $gen);
2143 # Pull out the version and timestamp from the line above
2144 ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\r?\Z/m;
2147 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"
2148 if !$self->overwrite_modifications && Digest::MD5::md5_base64(encode 'UTF-8', $gen) ne $md5;
2157 my $custom = do { local $/; <$fh> }
2161 $custom =~ s/$CRLF|$LF/\n/g;
2165 return ($gen, $md5, $ver, $ts, $custom);
2173 warn "$target: use $_;" if $self->debug;
2174 $self->_raw_stmt($target, "use $_;");
2182 my $blist = join(q{ }, @_);
2184 return unless $blist;
2186 warn "$target: use base qw/$blist/;" if $self->debug;
2187 $self->_raw_stmt($target, "use base qw/$blist/;");
2194 my $rlist = join(q{, }, map { qq{'$_'} } @_);
2196 return unless $rlist;
2198 warn "$target: with $rlist;" if $self->debug;
2199 $self->_raw_stmt($target, "\nwith $rlist;");
2202 sub _result_namespace {
2203 my ($self, $schema_class, $ns) = @_;
2204 my @result_namespace;
2206 $ns = $ns->[0] if ref $ns;
2208 if ($ns =~ /^\+(.*)/) {
2209 # Fully qualified namespace
2210 @result_namespace = ($1)
2213 # Relative namespace
2214 @result_namespace = ($schema_class, $ns);
2217 return wantarray ? @result_namespace : join '::', @result_namespace;
2220 # Create class with applicable bases, setup monikers, etc
2221 sub _make_src_class {
2222 my ($self, $table) = @_;
2224 my $schema = $self->schema;
2225 my $schema_class = $self->schema_class;
2227 my $table_moniker = $self->monikers->{$table->sql_name};
2228 my @result_namespace = ($schema_class);
2229 if ($self->use_namespaces) {
2230 my $result_namespace = $self->result_namespace || 'Result';
2231 @result_namespace = $self->_result_namespace(
2236 my $table_class = join(q{::}, @result_namespace, $table_moniker);
2238 if ((my $upgrading_v = $self->_upgrading_from)
2239 || $self->_rewriting) {
2240 local $self->naming->{monikers} = $upgrading_v
2243 my @result_namespace = @result_namespace;
2244 if ($self->_upgrading_from_load_classes) {
2245 @result_namespace = ($schema_class);
2247 elsif (my $ns = $self->_downgrading_to_load_classes) {
2248 @result_namespace = $self->_result_namespace(
2253 elsif ($ns = $self->_rewriting_result_namespace) {
2254 @result_namespace = $self->_result_namespace(
2260 my $old_table_moniker = do {
2261 local $self->naming->{monikers} = $upgrading_v;
2262 $self->_table2moniker($table);
2265 my $old_class = join(q{::}, @result_namespace, $old_table_moniker);
2267 $self->_upgrading_classes->{$table_class} = $old_class
2268 unless $table_class eq $old_class;
2271 $self->classes->{$table->sql_name} = $table_class;
2272 $self->moniker_to_table->{$table_moniker} = $table;
2273 $self->class_to_table->{$table_class} = $table;
2275 $self->_pod_class_list($table_class, 'ADDITIONAL CLASSES USED', @{$self->additional_classes});
2277 $self->_use ($table_class, @{$self->additional_classes});
2279 $self->_pod_class_list($table_class, 'LEFT BASE CLASSES', @{$self->left_base_classes});
2281 $self->_inject($table_class, @{$self->left_base_classes});
2283 my @components = @{ $self->components || [] };
2285 push @components, @{ $self->result_components_map->{$table_moniker} }
2286 if exists $self->result_components_map->{$table_moniker};
2288 my @fq_components = @components;
2289 foreach my $component (@fq_components) {
2290 if ($component !~ s/^\+//) {
2291 $component = "DBIx::Class::$component";
2295 $self->_pod_class_list($table_class, 'COMPONENTS LOADED', @fq_components);
2297 $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
2299 $self->_pod_class_list($table_class, 'ADDITIONAL BASE CLASSES', @{$self->additional_base_classes});
2301 $self->_inject($table_class, @{$self->additional_base_classes});
2304 sub _is_result_class_method {
2305 my ($self, $name, $table) = @_;
2307 my $table_moniker = $table ? $self->monikers->{$table->sql_name} : '';
2309 $self->_result_class_methods({})
2310 if not defined $self->_result_class_methods;
2312 if (not exists $self->_result_class_methods->{$table_moniker}) {
2313 my (@methods, %methods);
2314 my $base = $self->result_base_class || 'DBIx::Class::Core';
2316 my @components = @{ $self->components || [] };
2318 push @components, @{ $self->result_components_map->{$table_moniker} }
2319 if exists $self->result_components_map->{$table_moniker};
2321 for my $c (@components) {
2322 $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
2325 my @roles = @{ $self->result_roles || [] };
2327 push @roles, @{ $self->result_roles_map->{$table_moniker} }
2328 if exists $self->result_roles_map->{$table_moniker};
2330 for my $class ($base, @components,
2331 ($self->use_moose ? 'Moose::Object' : ()), @roles) {
2332 $self->ensure_class_loaded($class);
2334 push @methods, @{ Class::Inspector->methods($class) || [] };
2337 push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
2339 @methods{@methods} = ();
2341 $self->_result_class_methods->{$table_moniker} = \%methods;
2343 my $result_methods = $self->_result_class_methods->{$table_moniker};
2345 return exists $result_methods->{$name};
2348 sub _resolve_col_accessor_collisions {
2349 my ($self, $table, $col_info) = @_;
2351 while (my ($col, $info) = each %$col_info) {
2352 my $accessor = $info->{accessor} || $col;
2354 next if $accessor eq 'id'; # special case (very common column)
2356 if ($self->_is_result_class_method($accessor, $table)) {
2359 if (my $map = $self->col_collision_map) {
2360 for my $re (keys %$map) {
2361 if (my @matches = $col =~ /$re/) {
2362 $info->{accessor} = sprintf $map->{$re}, @matches;
2370 Column '$col' in table '$table' collides with an inherited method.
2371 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
2373 $info->{accessor} = undef;
2379 # use the same logic to run moniker_map, col_accessor_map
2381 my ( $self, $map, $default_code, $ident, @extra ) = @_;
2383 my $default_ident = $default_code->( $ident, @extra );
2385 if( $map && ref $map eq 'HASH' ) {
2386 if (my @parts = try{ @{ $ident } }) {
2387 my $part_map = $map;
2389 my $part = shift @parts;
2390 last unless exists $part_map->{ $part };
2391 if ( !ref $part_map->{ $part } && !@parts ) {
2392 $new_ident = $part_map->{ $part };
2395 elsif ( ref $part_map->{ $part } eq 'HASH' ) {
2396 $part_map = $part_map->{ $part };
2400 if( !$new_ident && !ref $map->{ $ident } ) {
2401 $new_ident = $map->{ $ident };
2404 elsif( $map && ref $map eq 'CODE' ) {
2405 $new_ident = $map->( $ident, $default_ident, @extra );
2408 $new_ident ||= $default_ident;
2413 sub _default_column_accessor_name {
2414 my ( $self, $column_name ) = @_;
2416 my $preserve = ($self->naming->{column_accessors}||'') eq 'preserve';
2418 my $v = $self->_get_naming_v('column_accessors');
2420 my $accessor_name = $preserve ?
2421 $self->_to_identifier('column_accessors', $column_name) # assume CamelCase
2423 $self->_to_identifier('column_accessors', $column_name, '_');
2425 $accessor_name =~ s/\W+/_/g; # only if naming < v8, otherwise to_identifier
2429 return $accessor_name;
2431 elsif ($v < 7 || (not $self->preserve_case)) {
2432 # older naming just lc'd the col accessor and that's all.
2433 return lc $accessor_name;
2436 return join '_', map lc, split_name $column_name, $v;
2439 sub _make_column_accessor_name {
2440 my ($self, $column_name, $column_context_info ) = @_;
2442 my $accessor = $self->_run_user_map(
2443 $self->col_accessor_map,
2444 sub { $self->_default_column_accessor_name( shift ) },
2446 $column_context_info,
2452 # Set up metadata (cols, pks, etc)
2453 sub _setup_src_meta {
2454 my ($self, $table) = @_;
2456 my $schema = $self->schema;
2457 my $schema_class = $self->schema_class;
2459 my $table_class = $self->classes->{$table->sql_name};
2460 my $table_moniker = $self->monikers->{$table->sql_name};
2462 $self->_dbic_stmt($table_class, 'table', $table->dbic_name);
2464 my $cols = $self->_table_columns($table);
2465 my $col_info = $self->__columns_info_for($table);
2467 ### generate all the column accessor names
2468 while (my ($col, $info) = each %$col_info) {
2469 # hashref of other info that could be used by
2470 # user-defined accessor map functions
2472 table_class => $table_class,
2473 table_moniker => $table_moniker,
2474 table_name => $table, # bugwards compatibility, RT#84050
2476 full_table_name => $table->dbic_name,
2477 schema_class => $schema_class,
2478 column_info => $info,
2481 $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
2484 $self->_resolve_col_accessor_collisions($table, $col_info);
2486 # prune any redundant accessor names
2487 while (my ($col, $info) = each %$col_info) {
2488 no warnings 'uninitialized';
2489 delete $info->{accessor} if $info->{accessor} eq $col;
2492 my $fks = $self->_table_fk_info($table);
2494 foreach my $fkdef (@$fks) {
2495 for my $col (@{ $fkdef->{local_columns} }) {
2496 $col_info->{$col}{is_foreign_key} = 1;
2500 my $pks = $self->_table_pk_info($table) || [];
2502 my %uniq_tag; # used to eliminate duplicate uniqs
2504 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
2506 my $uniqs = $self->_table_uniq_info($table) || [];
2509 foreach my $uniq (@$uniqs) {
2510 my ($name, $cols) = @$uniq;
2511 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
2512 push @uniqs, [$name, $cols];
2515 my @non_nullable_uniqs = grep {
2516 all { $col_info->{$_}{is_nullable} == 0 } @{ $_->[1] }
2519 if ($self->uniq_to_primary && (not @$pks) && @non_nullable_uniqs) {
2520 my @by_colnum = sort { $b->[0] <=> $a->[0] }
2521 map [ scalar @{ $_->[1] }, $_ ], @non_nullable_uniqs;
2523 if (not (@by_colnum > 1 && $by_colnum[0][0] == $by_colnum[1][0])) {
2524 my @keys = map $_->[1], @by_colnum;
2528 # remove the uniq from list
2529 @uniqs = grep { $_->[0] ne $pk->[0] } @uniqs;
2535 foreach my $pkcol (@$pks) {
2536 $col_info->{$pkcol}{is_nullable} = 0;
2542 map { $_, ($col_info->{$_}||{}) } @$cols
2545 $self->_dbic_stmt($table_class, 'set_primary_key', @$pks)
2548 # Sort unique constraints by constraint name for repeatable results (rels
2549 # are sorted as well elsewhere.)
2550 @uniqs = sort { $a->[0] cmp $b->[0] } @uniqs;
2552 foreach my $uniq (@uniqs) {
2553 my ($name, $cols) = @$uniq;
2554 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
2558 sub __columns_info_for {
2559 my ($self, $table) = @_;
2561 my $result = $self->_columns_info_for($table);
2563 while (my ($col, $info) = each %$result) {
2564 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
2565 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
2567 $result->{$col} = $info;
2575 Returns a sorted list of loaded tables, using the original database table
2583 return values %{$self->_tables};
2587 my ($self, $naming_key) = @_;
2591 if (($self->naming->{$naming_key}||'') =~ /^v(\d+)\z/) {
2595 ($v) = $CURRENT_V =~ /^v(\d+)\z/;
2601 sub _to_identifier {
2602 my ($self, $naming_key, $name, $sep_char, $force) = @_;
2604 my $v = $self->_get_naming_v($naming_key);
2606 my $to_identifier = $self->naming->{force_ascii} ?
2607 \&String::ToIdentifier::EN::to_identifier
2608 : \&String::ToIdentifier::EN::Unicode::to_identifier;
2610 return $v >= 8 || $force ? $to_identifier->($name, $sep_char) : $name;
2613 # Make a moniker from a table
2614 sub _default_table2moniker {
2615 my ($self, $table) = @_;
2617 my $v = $self->_get_naming_v('monikers');
2619 my @name_parts = map $table->$_, @{ $self->moniker_parts };
2621 my $name_idx = firstidx { $_ eq 'name' } @{ $self->moniker_parts };
2625 foreach my $i (0 .. $#name_parts) {
2626 my $part = $name_parts[$i];
2628 if ($i != $name_idx || $v >= 8) {
2629 $part = $self->_to_identifier('monikers', $part, '_', 1);
2632 if ($i == $name_idx && $v == 5) {
2633 $part = Lingua::EN::Inflect::Number::to_S($part);
2636 my @part_parts = map lc, $v > 6 ?
2637 # use v8 semantics for all moniker parts except name
2638 ($i == $name_idx ? split_name $part, $v : split_name $part)
2639 : split /[\W_]+/, $part;
2641 if ($i == $name_idx && $v >= 6) {
2642 my $as_phrase = join ' ', @part_parts;
2644 my $inflected = ($self->naming->{monikers}||'') eq 'plural' ?
2645 Lingua::EN::Inflect::Phrase::to_PL($as_phrase)
2647 ($self->naming->{monikers}||'') eq 'preserve' ?
2650 Lingua::EN::Inflect::Phrase::to_S($as_phrase);
2652 @part_parts = split /\s+/, $inflected;
2655 push @all_parts, join '', map ucfirst, @part_parts;
2658 return join $self->moniker_part_separator, @all_parts;
2661 sub _table2moniker {
2662 my ( $self, $table ) = @_;
2664 $self->_run_user_map(
2666 sub { $self->_default_table2moniker( shift ) },
2671 sub _load_relationships {
2672 my ($self, $tables) = @_;
2676 foreach my $table (@$tables) {
2677 my $local_moniker = $self->monikers->{$table->sql_name};
2679 my $tbl_fk_info = $self->_table_fk_info($table);
2681 foreach my $fkdef (@$tbl_fk_info) {
2682 $fkdef->{local_table} = $table;
2683 $fkdef->{local_moniker} = $local_moniker;
2684 $fkdef->{remote_source} =
2685 $self->monikers->{$fkdef->{remote_table}->sql_name};
2687 my $tbl_uniq_info = $self->_table_uniq_info($table);
2689 push @tables, [ $local_moniker, $tbl_fk_info, $tbl_uniq_info ];
2692 my $rel_stmts = $self->_relbuilder->generate_code(\@tables);
2694 foreach my $src_class (sort keys %$rel_stmts) {
2696 my @src_stmts = map $_->[2],
2702 ($_->{method} eq 'many_to_many' ? 1 : 0),
2705 ], @{ $rel_stmts->{$src_class} };
2707 foreach my $stmt (@src_stmts) {
2708 $self->_dbic_stmt($src_class,$stmt->{method}, @{$stmt->{args}});
2714 my ($self, $table) = @_;
2716 my $table_moniker = $self->monikers->{$table->sql_name};
2717 my $table_class = $self->classes->{$table->sql_name};
2719 my @roles = @{ $self->result_roles || [] };
2720 push @roles, @{ $self->result_roles_map->{$table_moniker} }
2721 if exists $self->result_roles_map->{$table_moniker};
2724 $self->_pod_class_list($table_class, 'L<Moose> ROLES APPLIED', @roles);
2726 $self->_with($table_class, @roles);
2730 # Overload these in driver class:
2732 # Returns an arrayref of column names
2733 sub _table_columns { croak "ABSTRACT METHOD" }
2735 # Returns arrayref of pk col names
2736 sub _table_pk_info { croak "ABSTRACT METHOD" }
2738 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
2739 sub _table_uniq_info { croak "ABSTRACT METHOD" }
2741 # Returns an arrayref of foreign key constraints, each
2742 # being a hashref with 3 keys:
2743 # local_columns (arrayref), remote_columns (arrayref), remote_table
2744 sub _table_fk_info { croak "ABSTRACT METHOD" }
2746 # Returns an array of lower case table names
2747 sub _tables_list { croak "ABSTRACT METHOD" }
2749 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
2755 # generate the pod for this statement, storing it with $self->_pod
2756 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
2758 my $args = dump(@_);
2759 $args = '(' . $args . ')' if @_ < 2;
2760 my $stmt = $method . $args . q{;};
2762 warn qq|$class\->$stmt\n| if $self->debug;
2763 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
2767 sub _make_pod_heading {
2768 my ($self, $class) = @_;
2770 return '' if not $self->generate_pod;
2772 my $table = $self->class_to_table->{$class};
2775 my $pcm = $self->pod_comment_mode;
2776 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
2777 $comment = $self->__table_comment($table);
2778 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
2779 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
2780 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
2782 $pod .= "=head1 NAME\n\n";
2784 my $table_descr = $class;
2785 $table_descr .= " - " . $comment if $comment and $comment_in_name;
2787 $pod .= "$table_descr\n\n";
2789 if ($comment and $comment_in_desc) {
2790 $pod .= "=head1 DESCRIPTION\n\n${comment}\n\n";
2797 # generates the accompanying pod for a DBIC class method statement,
2798 # storing it with $self->_pod
2804 if ($method eq 'table') {
2806 $table = $$table if ref $table eq 'SCALAR';
2807 $self->_pod($class, "=head1 TABLE: C<$table>");
2808 $self->_pod_cut($class);
2810 elsif ( $method eq 'add_columns' ) {
2811 $self->_pod( $class, "=head1 ACCESSORS" );
2812 my $col_counter = 0;
2814 while( my ($name,$attrs) = splice @cols,0,2 ) {
2816 $self->_pod( $class, '=head2 ' . $name );
2817 $self->_pod( $class,
2819 my $s = $attrs->{$_};
2820 $s = !defined $s ? 'undef' :
2821 length($s) == 0 ? '(empty string)' :
2822 ref($s) eq 'SCALAR' ? $$s :
2823 ref($s) ? dumper_squashed $s :
2824 looks_like_number($s) ? $s : qq{'$s'};
2827 } sort keys %$attrs,
2829 if (my $comment = $self->__column_comment($self->class_to_table->{$class}, $col_counter, $name)) {
2830 $self->_pod( $class, $comment );
2833 $self->_pod_cut( $class );
2834 } elsif ( $method =~ /^(?:belongs_to|has_many|might_have)\z/ ) {
2835 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2836 my ( $accessor, $rel_class ) = @_;
2837 $self->_pod( $class, "=head2 $accessor" );
2838 $self->_pod( $class, 'Type: ' . $method );
2839 $self->_pod( $class, "Related object: L<$rel_class>" );
2840 $self->_pod_cut( $class );
2841 $self->{_relations_started} { $class } = 1;
2842 } elsif ( $method eq 'many_to_many' ) {
2843 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2844 my ( $accessor, $rel1, $rel2 ) = @_;
2845 $self->_pod( $class, "=head2 $accessor" );
2846 $self->_pod( $class, 'Type: many_to_many' );
2847 $self->_pod( $class, "Composing rels: L</$rel1> -> $rel2" );
2848 $self->_pod_cut( $class );
2849 $self->{_relations_started} { $class } = 1;
2851 elsif ($method eq 'add_unique_constraint') {
2852 $self->_pod($class, '=head1 UNIQUE CONSTRAINTS')
2853 unless $self->{_uniqs_started}{$class};
2855 my ($name, $cols) = @_;
2857 $self->_pod($class, "=head2 C<$name>");
2858 $self->_pod($class, '=over 4');
2860 foreach my $col (@$cols) {
2861 $self->_pod($class, "=item \* L</$col>");
2864 $self->_pod($class, '=back');
2865 $self->_pod_cut($class);
2867 $self->{_uniqs_started}{$class} = 1;
2869 elsif ($method eq 'set_primary_key') {
2870 $self->_pod($class, "=head1 PRIMARY KEY");
2871 $self->_pod($class, '=over 4');
2873 foreach my $col (@_) {
2874 $self->_pod($class, "=item \* L</$col>");
2877 $self->_pod($class, '=back');
2878 $self->_pod_cut($class);
2882 sub _pod_class_list {
2883 my ($self, $class, $title, @classes) = @_;
2885 return unless @classes && $self->generate_pod;
2887 $self->_pod($class, "=head1 $title");
2888 $self->_pod($class, '=over 4');
2890 foreach my $link (@classes) {
2891 $self->_pod($class, "=item * L<$link>");
2894 $self->_pod($class, '=back');
2895 $self->_pod_cut($class);
2898 sub _base_class_pod {
2899 my ($self, $base_class) = @_;
2901 return '' unless $self->generate_pod;
2904 =head1 BASE CLASS: L<$base_class>
2911 sub _filter_comment {
2912 my ($self, $txt) = @_;
2914 $txt = '' if not defined $txt;
2916 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2921 sub __table_comment {
2924 if (my $code = $self->can('_table_comment')) {
2925 return $self->_filter_comment($self->$code(@_));
2931 sub __column_comment {
2934 if (my $code = $self->can('_column_comment')) {
2935 return $self->_filter_comment($self->$code(@_));
2941 # Stores a POD documentation
2943 my ($self, $class, $stmt) = @_;
2944 $self->_raw_stmt( $class, "\n" . $stmt );
2948 my ($self, $class ) = @_;
2949 $self->_raw_stmt( $class, "\n=cut\n" );
2952 # Store a raw source line for a class (for dumping purposes)
2954 my ($self, $class, $stmt) = @_;
2955 push(@{$self->{_dump_storage}->{$class}}, $stmt);
2958 # Like above, but separately for the externally loaded stuff
2960 my ($self, $class, $stmt) = @_;
2961 push(@{$self->{_ext_storage}->{$class}}, $stmt);
2964 sub _custom_column_info {
2965 my ( $self, $table_name, $column_name, $column_info ) = @_;
2967 if (my $code = $self->custom_column_info) {
2968 return $code->($table_name, $column_name, $column_info) || {};
2973 sub _datetime_column_info {
2974 my ( $self, $table_name, $column_name, $column_info ) = @_;
2976 my $type = $column_info->{data_type} || '';
2977 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2978 or ($type =~ /date|timestamp/i)) {
2979 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2980 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
2986 my ($self, $name) = @_;
2988 return $self->preserve_case ? $name : lc($name);
2992 my ($self, $name) = @_;
2994 return $self->preserve_case ? $name : uc($name);
2998 my ($self, $table) = @_;
3001 my $schema = $self->schema;
3002 # in older DBIC it's a private method
3003 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
3004 $schema->$unregister(delete $self->monikers->{$table->sql_name});
3005 delete $self->_upgrading_classes->{delete $self->classes->{$table->sql_name}};
3006 delete $self->_tables->{$table->sql_name};
3010 # remove the dump dir from @INC on destruction
3014 @INC = grep $_ ne $self->dump_directory, @INC;
3019 Returns a hashref of loaded table to moniker mappings. There will
3020 be two entries for each table, the original name and the "normalized"
3021 name, in the case that the two are different (such as databases
3022 that like uppercase table names, or preserve your original mixed-case
3023 definitions, or what-have-you).
3027 Returns a hashref of table to class mappings. In some cases it will
3028 contain multiple entries per table for the original and normalized table
3029 names, as above in L</monikers>.
3031 =head1 NON-ENGLISH DATABASES
3033 If you use the loader on a database with table and column names in a language
3034 other than English, you will want to turn off the English language specific
3037 To do so, use something like this in your loader options:
3039 naming => { monikers => 'v4' },
3040 inflect_singular => sub { "$_[0]_rel" },
3041 inflect_plural => sub { "$_[0]_rel" },
3043 =head1 COLUMN ACCESSOR COLLISIONS
3045 Occasionally you may have a column name that collides with a perl method, such
3046 as C<can>. In such cases, the default action is to set the C<accessor> of the
3047 column spec to C<undef>.
3049 You can then name the accessor yourself by placing code such as the following
3052 __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
3054 Another option is to use the L</col_collision_map> option.
3056 =head1 RELATIONSHIP NAME COLLISIONS
3058 In very rare cases, you may get a collision between a generated relationship
3059 name and a method in your Result class, for example if you have a foreign key
3060 called C<belongs_to>.
3062 This is a problem because relationship names are also relationship accessor
3063 methods in L<DBIx::Class>.
3065 The default behavior is to append C<_rel> to the relationship name and print
3066 out a warning that refers to this text.
3068 You can also control the renaming with the L</rel_collision_map> option.
3072 L<DBIx::Class::Schema::Loader>, L<dbicdump>
3076 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
3080 This library is free software; you can redistribute it and/or modify it under
3081 the same terms as Perl itself.
3086 # vim:et sts=4 sw=4 tw=0: