1 package DBIx::Class::Loader::Generic;
4 use base 'DBIx::Class::Componentised';
6 use Lingua::EN::Inflect;
7 use UNIVERSAL::require;
8 require DBIx::Class::DB;
9 require DBIx::Class::Core;
13 DBIx::Class::Loader::Generic - Generic DBIx::Class::Loader Implementation.
17 See L<DBIx::Class::Loader>
23 Available constructor options are:
25 =head3 additional_base_classes
27 List of additional base classes your table classes will use.
29 =head3 left_base_classes
31 List of additional base classes, that need to be leftmost.
33 =head3 additional_classes
35 List of additional classes which your table classes will use.
39 Only load tables matching regex.
43 Exclude tables matching regex.
47 Enable debug messages.
55 Namespace under which your table classes will be initialized.
63 Try to automatically detect/setup has_a and has_many relationships.
67 An hashref, which contains exceptions to Lingua::EN::Inflect::PL().
68 Useful for foreign language column names.
80 Not intended to be called directly. This is used internally by the
81 C<new()> method in L<DBIx::Class::Loader>.
86 my ( $class, %args ) = @_;
89 *{"$class\::debug"} = sub { 1 };
91 my $additional = $args{additional_classes} || [];
92 $additional = [$additional] unless ref $additional eq 'ARRAY';
93 my $additional_base = $args{additional_base_classes} || [];
94 $additional_base = [$additional_base]
95 unless ref $additional_base eq 'ARRAY';
96 my $left_base = $args{left_base_classes} || [];
97 $left_base = [$left_base] unless ref $left_base eq 'ARRAY';
100 [ $args{dsn}, $args{user}, $args{password}, $args{options} ],
101 _namespace => $args{namespace},
102 _additional => $additional,
103 _additional_base => $additional_base,
104 _left_base => $left_base,
105 _constraint => $args{constraint} || '.*',
106 _exclude => $args{exclude},
107 _relationships => $args{relationships},
108 _inflect => $args{inflect},
109 _schema => $args{schema},
110 _dropschema => $args{dropschema},
113 warn qq/\### START DBIx::Class::Loader dump ###\n/ if $self->debug;
114 $self->_load_classes;
115 $self->_relationships if $self->{_relationships};
116 warn qq/\### END DBIx::Class::Loader dump ###\n/ if $self->debug;
122 Returns a tables class.
124 my $class = $loader->find_class($table);
129 my ( $self, $table ) = @_;
130 return $self->{CLASSES}->{$table};
135 Returns a sorted list of classes.
137 my $@classes = $loader->classes;
143 return sort values %{ $self->{CLASSES} };
148 Overload to enable debug messages.
156 Returns a sorted list of tables.
158 my @tables = $loader->tables;
164 return sort keys %{ $self->{CLASSES} };
167 # Overload in your driver class
168 sub _db_classes { croak "ABSTRACT METHOD" }
170 # Setup has_a and has_many relationships
171 sub _belongs_to_many {
172 my ( $self, $table, $column, $other, $other_column ) = @_;
173 my $table_class = $self->find_class($table);
174 my $other_class = $self->find_class($other);
176 warn qq/\# Belongs_to relationship\n/ if $self->debug;
179 warn qq/$table_class->belongs_to( '$column' => '$other_class',/
180 . qq/ { "foreign.$other_column" => "self.$column" },/
181 . qq/ { accessor => 'filter' });\n\n/
183 $table_class->belongs_to( $column => $other_class,
184 { "foreign.$other_column" => "self.$column" },
185 { accessor => 'filter' }
189 warn qq/$table_class->belongs_to( '$column' => '$other_class' );\n\n/
191 $table_class->belongs_to( $column => $other_class );
194 my ($table_class_base) = $table_class =~ /.*::(.+)/;
195 my $plural = Lingua::EN::Inflect::PL( lc $table_class_base );
196 $plural = $self->{_inflect}->{ lc $table_class_base }
198 and exists $self->{_inflect}->{ lc $table_class_base };
200 warn qq/\# Has_many relationship\n/ if $self->debug;
203 warn qq/$other_class->has_many( '$plural' => '$table_class',/
204 . qq/ { "foreign.$column" => "self.$other_column" } );\n\n/
206 $other_class->has_many( $plural => $table_class,
207 { "foreign.$column" => "self.$other_column" }
211 warn qq/$other_class->has_many( '$plural' => '$table_class',/
212 . qq/'$other_column' );\n\n/
214 $other_class->has_many( $plural => $table_class, $column );
218 # Load and setup classes
221 my @schema = ('schema' => $self->{_schema}) if($self->{_schema});
222 my @tables = $self->_tables(@schema);
223 my @db_classes = $self->_db_classes();
224 my $additional = join '', map "use $_;\n", @{ $self->{_additional} };
225 my $additional_base = join '', map "use base '$_';\n",
226 @{ $self->{_additional_base} };
227 my $left_base = join '', map "use base '$_';\n", @{ $self->{_left_base} };
228 my $constraint = $self->{_constraint};
229 my $exclude = $self->{_exclude};
231 my $namespace = $self->{_namespace};
232 my $dbclass = "$namespace\::_db";
233 $self->inject_base( $dbclass, 'DBIx::Class::DB' );
234 $dbclass->connection( @{ $self->{_datasource} } );
236 foreach my $table (@tables) {
237 next unless $table =~ /$constraint/;
238 next if ( defined $exclude && $table =~ /$exclude/ );
239 my ($schema, $tbl) = split /\./, $table;
240 my $tablename = lc $table;
242 $tablename = $self->{_dropschema} ? $tbl : lc $table;
244 my $class = $self->_table2class($schema, $tbl);
245 $self->inject_base( $class, $dbclass, 'DBIx::Class::Core' );
246 $_->require for @db_classes;
247 $self->inject_base( $class, $_ ) for @db_classes;
248 warn qq/\# Initializing table "$table" as "$class"\n/ if $self->debug;
249 $class->table(lc $tablename);
250 my ( $cols, $pks ) = $self->_table_info($table);
251 carp("$table has no primary key") unless @$pks;
252 $class->add_columns(@$cols);
253 $class->set_primary_key(@$pks) if @$pks;
254 $self->{CLASSES}->{lc $tablename} = $class;
255 my $code = "package $class;\n$additional_base$additional$left_base";
256 warn qq/$code/ if $self->debug;
257 warn qq/$class->table('$tablename');\n/ if $self->debug;
258 my $columns = join "', '", @$cols;
259 warn qq/$class->add_columns('$columns')\n/ if $self->debug;
260 my $primaries = join "', '", @$pks;
261 warn qq/$class->set_primary_key('$primaries')\n/ if $self->debug && @$pks;
263 croak qq/Couldn't load additional classes "$@"/ if $@;
264 unshift @{"$class\::ISA"}, $_ foreach ( @{ $self->{_left_base} } );
268 # Find and setup relationships
271 foreach my $table ( $self->tables ) {
272 my $dbh = $self->find_class($table)->storage->dbh;
273 my $quoter = $dbh->get_info(29) || q{"};
274 if ( my $sth = $dbh->foreign_key_info( '', '', '', '', '', $table ) ) {
275 for my $res ( @{ $sth->fetchall_arrayref( {} ) } ) {
276 my $column = $res->{FK_COLUMN_NAME};
277 my $other = $res->{UK_TABLE_NAME};
278 my $other_column = $res->{UK_COLUMN_NAME};
279 $column =~ s/$quoter//g;
280 $other =~ s/$quoter//g;
281 $other_column =~ s/$quoter//g;
282 eval { $self->_belongs_to_many( $table, $column, $other,
284 warn qq/\# belongs_to_many failed "$@"\n\n/
285 if $@ && $self->debug;
291 # Make a class from a table
293 my ( $self, $schema, $table ) = @_;
294 my $namespace = $self->{_namespace} || "";
295 $namespace =~ s/(.*)::$/$1/;
297 $schema = ucfirst lc $schema;
298 $namespace .= "::$schema" if(!$self->{_dropschema});
302 my $subclass = join '', map ucfirst, split /[\W_]+/, lc $table;
303 my $class = $namespace ? "$namespace\::" . $subclass : $subclass;
306 # Overload in driver class
307 sub _tables { croak "ABSTRACT METHOD" }
309 sub _table_info { croak "ABSTRACT METHOD" }
313 L<DBIx::Class::Loader>