4a9852e752a6063fc0c1f37ad2d1a96392607a5c
[dbsrgits/DBIx-Class-Schema-ResultSetAccessors.git] / lib / DBIx / Class / Schema / ResultSetAccessors.pm
1 package DBIx::Class::Schema::ResultSetAccessors;
2
3 use strict;
4 use warnings;
5
6 use base 'DBIx::Class::AccessorGroup';
7
8 use DBIx::Class::Carp qw(carp);
9 use String::CamelCase;
10 use Lingua::EN::Inflect::Phrase;
11 use Sub::Name 'subname';
12 use namespace::clean;
13
14 our $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({});
22
23 sub register_source {
24     my $self    = shift;
25     my $moniker = $_[0];
26     my $next    = $self->next::method(@_);
27     my $schema  = ref($self) || $self;
28
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
35     my $accessor_name =
36         exists $self->resultset_accessor_map->{$moniker}
37              ? $self->resultset_accessor_map->{$moniker}
38              : $self->resultset_accessor_name($moniker);
39
40     if ($schema->can($accessor_name)) {
41         carp(
42             "Can't create ResultSet accessor '$accessor_name'. " .
43             "Schema method with the same name already exists. " .
44             "Try overloading the name via resultset_accessor_map."
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     }
54
55     $self->_track_resultset_accessors->{$schema}{$moniker} = 1;
56
57     return $next;
58 }
59
60 sub resultset_accessor_name {
61     my ($self, $moniker) = @_;
62
63     return $self->pluralize_resultset_accessor_name(
64         String::CamelCase::decamelize($moniker)
65     );
66 }
67
68 sub pluralize_resultset_accessor_name {
69     my ($self, $original) = @_;
70
71     return join '_', split /\s+/,
72         Lingua::EN::Inflect::Phrase::to_PL(join ' ', split /_/, $original);
73 }
74
75 1; # eof
76
77 __END__
78
79 =head1 NAME
80
81 DBIx::Class::Schema::ResultSetAccessors - Short hand ResultSet Accessors
82
83 =head1 SYNOPSIS
84
85   # in your schema class
86   __PACKAGE__->load_components(qw/
87       Schema::ResultSetAccessors
88   /);
89   __PACKAGE__->load_namespaces;
90
91   # in your program
92   use MyApp::Schema;
93   my $schema = MyApp::Schema->connect(...);
94   @artists = $schema->artists->all; # same as $schema->resultset('Artist')->all;
95
96 =head1 DESCRIPTION
97
98 Creates short hand accessor methods for each ResultSet. Accessor names are
99 properly 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
109 Sometimes you will not want to, or will not be able to use an auto-generated
110 accessor name. A common case would be when the accessor name conflicts with a
111 built 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
113 method.
114
115 This method allows you to redefine the names as you wish. Overload this method
116 in 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     {
121         Source => 'my_sources',
122         Artist => 'my_artists',
123     }
124  }
125
126  # later in your code
127  $schema->my_sources->all;
128
129 =head2 resultset_accessor_name($moniker)
130
131 This method is used to generate the accessor names. If you wish to create your
132 own logic for generating the name, you can overload this method. The method
133 takes a moniker (aka Source name) as a parameter and returns the accessor name.
134
135 Internally it simply uses L<String::CamelCase> to decamelize the name and pass
136 it to L</pluralize_resultset_accessor_name> method.
137
138 =head2 pluralize_resultset_accessor_name($decamelized_name)
139
140 If you only wish to overload the pluralization of the accessor name, in case you
141 want to add support for a language other than English, then you might only want
142 to overload this method. The method accepts decamelized name (e.g. liner_note)
143 and 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
164 Copyright (c) 2011 Roman F.
165
166 This program is free software; you can redistribute
167 it and/or modify it under the same terms as Perl itself.
168
169 The full text of the license can be found in the
170 LICENSE file included with this module.
171
172 =cut