Fixed a bug where a sub class would re-run register_source and trigger carp. Minor...
[dbsrgits/DBIx-Class-Schema-ResultSetAccessors.git] / lib / DBIx / Class / Schema / ResultSetAccessors.pm
CommitLineData
731e8b3e 1package DBIx::Class::Schema::ResultSetAccessors;
2
3use strict;
4use warnings;
5
3469a10b 6use base 'DBIx::Class::AccessorGroup';
7
77c7c7a8 8use DBIx::Class::Carp qw(carp);
731e8b3e 9use String::CamelCase;
10use Lingua::EN::Inflect::Phrase;
11use Sub::Name 'subname';
be7d3f83 12use namespace::clean;
731e8b3e 13
3469a10b 14our $VERSION = 0.001005;
15
16__PACKAGE__->mk_group_accessors(inherited => qw/
17 resultset_accessor_map
18 _track_resultset_accessors
19/);
20__PACKAGE__->resultset_accessor_map({});
21__PACKAGE__->_track_resultset_accessors({});
6a11ca65 22
731e8b3e 23sub register_source {
6e3c6029 24 my $self = shift;
731e8b3e 25 my $moniker = $_[0];
6e3c6029 26 my $next = $self->next::method(@_);
27 my $schema = ref($self) || $self;
28
3469a10b 29 # need to track if we already ran register_source once, because
30 # it might be re-run in sub-class, like in the case of
31 # Catalyst::Model::DBIC::Schema via compose_namespaces
32 return $next if
33 exists $self->_track_resultset_accessors->{$schema}{$moniker};
34
6e3c6029 35 my $accessor_name =
36 exists $self->resultset_accessor_map->{$moniker}
37 ? $self->resultset_accessor_map->{$moniker}
38 : $self->resultset_accessor_name($moniker);
731e8b3e 39
731e8b3e 40 if ($schema->can($accessor_name)) {
77c7c7a8 41 carp(
731e8b3e 42 "Can't create ResultSet accessor '$accessor_name'. " .
43 "Schema method with the same name already exists. " .
6e3c6029 44 "Try overloading the name via resultset_accessor_map."
731e8b3e 45 );
46 }
47
48 {
49 no strict 'refs';
50 no warnings 'redefine';
51 *{"${schema}::${accessor_name}"} = subname "${schema}::${accessor_name}"
52 => sub { shift->resultset($moniker) };
53 }
731e8b3e 54
3469a10b 55 $self->_track_resultset_accessors->{$schema}{$moniker} = 1;
56
57 return $next;
731e8b3e 58}
59
60sub resultset_accessor_name {
61 my ($self, $moniker) = @_;
62
63 return $self->pluralize_resultset_accessor_name(
64 String::CamelCase::decamelize($moniker)
65 );
66}
67
68sub pluralize_resultset_accessor_name {
6e3c6029 69 my ($self, $original) = @_;
731e8b3e 70
867277b3 71 return join '_', split /\s+/,
6e3c6029 72 Lingua::EN::Inflect::Phrase::to_PL(join ' ', split /_/, $original);
731e8b3e 73}
74
751; # eof
76
77__END__
78
79=head1 NAME
80
81DBIx::Class::Schema::ResultSetAccessors - Short hand ResultSet Accessors
82
83=head1 SYNOPSIS
84
3469a10b 85 # in your schema class
86 __PACKAGE__->load_components(qw/
87 Schema::ResultSetAccessors
88 /);
89 __PACKAGE__->load_namespaces;
90
91 # in your program
731e8b3e 92 use MyApp::Schema;
93 my $schema = MyApp::Schema->connect(...);
731e8b3e 94 @artists = $schema->artists->all; # same as $schema->resultset('Artist')->all;
95
96=head1 DESCRIPTION
97
3469a10b 98Creates short hand accessor methods for each ResultSet. Accessor names are
731e8b3e 99properly converted into lowercase and pluralized. E.g.
100
101 LinerNote -> liner_notes
102 Artist -> artists
103 CD -> cds
104
105=head1 METHODS
106
107=head2 resultset_accessor_map
108
109Sometimes you will not want to, or will not be able to use an auto-generated
110accessor name. A common case would be when the accessor name conflicts with a
111built in DBIx::Class::Schema method. E.g. if you name your Result class
112"Source", a pluralized version of this would be "sources", which is a built in
113method.
114
115This method allows you to redefine the names as you wish. Overload this method
116in your schema class and return a hashref map of Source => accessor names. E.g.:
117
118 # in your MyApp::Schema class
119 sub resultset_accessor_map {
120 {
9d76ec7c 121 Source => 'my_sources',
731e8b3e 122 Artist => 'my_artists',
123 }
124 }
3469a10b 125
731e8b3e 126 # later in your code
3469a10b 127 $schema->my_sources->all;
731e8b3e 128
129=head2 resultset_accessor_name($moniker)
130
131This method is used to generate the accessor names. If you wish to create your
132own logic for generating the name, you can overload this method. The method
133takes a moniker (aka Source name) as a parameter and returns the accessor name.
134
135Internally it simply uses L<String::CamelCase> to decamelize the name and pass
136it to L</pluralize_resultset_accessor_name> method.
137
138=head2 pluralize_resultset_accessor_name($decamelized_name)
139
140If you only wish to overload the pluralization of the accessor name, in case you
141want to add support for a language other than English, then you might only want
142to overload this method. The method accepts decamelized name (e.g. liner_note)
143and returns properly pluralized version of it.
144
145=head1 SEE ALSO
146
147=over 4
148
149=item L<DBIx::Class>
150
151=item L<String::CamelCase>
152
153=item L<Lingua::EN::Inflect::Phrase>
154
155=back
156
157=head1 AUTHOR
158
159 Roman F.
160 romanf@cpan.org
161
162=head1 COPYRIGHT
163
164Copyright (c) 2011 Roman F.
165
166This program is free software; you can redistribute
167it and/or modify it under the same terms as Perl itself.
168
169The full text of the license can be found in the
170LICENSE file included with this module.
171
172=cut