File Coverage

blib/lib/CatalystX/CRUD/ControllerRole.pm
Criterion Covered Total %
statement 49 51 96.0
branch 18 28 64.2
condition 1 3 33.3
subroutine 7 7 100.0
pod 5 5 100.0
total 80 94 85.1


line stmt bran cond sub pod time code
1             package CatalystX::CRUD::ControllerRole;
2 6     6   4365 use Moose::Role;
  6         18  
  6         88  
3 6     6   36133 use Catalyst::Utils;
  6         22  
  6         4656  
4              
5             requires 'throw_error';
6             requires 'model_adapter';
7             requires 'model_name';
8              
9             has 'primary_key' => (
10             is => 'rw',
11             isa => 'String',
12             );
13              
14             =head2 get_primary_key( I<context>, I<pk_value> )
15              
16             Should return an array of the name of the field(s) to fetch() I<pk_value> from
17             and their respective values.
18              
19             The default behaviour is to return B<primary_key> and the
20             corresponding value(s) from I<pk_value>.
21              
22             However, if you have other unique fields in your schema, you
23             might return a unique field other than the primary key.
24             This allows for a more flexible URI scheme.
25              
26             A good example is Users. A User record might have a numerical id (uid)
27             and a username, both of which are unique. So if username 'foobar'
28             has a B<primary_key> (uid) of '1234', both these URIs could fetch the same
29             record:
30              
31             /uri/for/user/1234
32             /uri/for/user/foobar
33              
34             Again, the default behaviour is to return the B<primary_key> field name(s)
35             from config() (accessed via $self->primary_key) but you can override
36             get_primary_key() in your subclass to provide more flexibility.
37              
38             If your primary key is composed of multiple columns, your return value
39             should include all those columns and their values as extracted
40             from I<pk_value>. Multiple values are assumed to be joined with C<;;>.
41             See make_primary_key_string().
42              
43             =cut
44              
45             sub get_primary_key {
46 35     35 1 101 my ( $self, $c, $id ) = @_;
47 35 50 33     224 return () unless defined $id and length $id;
48 35         161 my $pk = $self->primary_key;
49 35         4660 my @ret;
50 35 100       101 if ( ref $pk ) {
51 1         8 my @val = split( m/;;/, $id );
52 1         3 for my $col (@$pk) {
53 3         9 push( @ret, $col => shift(@val) );
54             }
55             }
56             else {
57 34         83 @ret = ( $pk => $id );
58             }
59 35         134 return @ret;
60             }
61              
62             =head2 make_primary_key_string( I<object> )
63              
64             Using value of B<primary_string> constructs a URI-ready
65             string based on values in I<object>. I<object> is often
66             the value of:
67            
68             $c->stash->{object}
69              
70             but could be any object that has accessor methods with
71             the same names as the field(s) specified by B<primary_key>.
72              
73             Multiple values are joined with C<;;> and any C<;> or C</> characters
74             in the column values are URI-escaped.
75              
76             =cut
77              
78             sub make_primary_key_string {
79 18     18 1 1070 my ( $self, $obj ) = @_;
80 18         67 my $pk = $self->primary_key;
81 18         2366 my $id;
82 18 100       74 if ( ref $pk ) {
83 1         2 my @vals;
84 1         3 for my $field (@$pk) {
85 2         16 my $v = scalar $obj->$field;
86 2 50       15 $v = '' unless defined $v;
87 2         10 $v =~ s/;/\%3b/g;
88 2         6 push( @vals, $v );
89             }
90              
91             # if we had no vals, return undef
92 1 50       2 if ( !grep {length} @vals ) {
  2         6  
93 0         0 return $id;
94             }
95              
96 1         5 $id = join( ';;', @vals );
97             }
98             else {
99 17         66 $id = $obj->$pk;
100             }
101              
102 18 50       2051 return $id unless defined $id;
103              
104             # must escape any / in $id since passing it to uri_for as-is
105             # will break.
106 18         79 $id =~ s!/!\%2f!g;
107              
108 18         57 return $id;
109             }
110              
111             =head2 instantiate_model_adapter( I<app_class> )
112              
113             If model_adapter() is set to a string of the adapter class
114             name, this method will instantiate
115             the model_adapter with its new() method, passing in
116             model_name(), model_meta() and I<app_class>.
117              
118             =cut
119              
120             sub instantiate_model_adapter {
121 26     26 1 58 my $self = shift;
122 26 50       76 my $app_class = shift or $self->throw_error("app_class required");
123              
124             # if model_adapter class is defined, load and instantiate it.
125 26 100       143 if ( $self->model_adapter ) {
126 12         1670 Catalyst::Utils::ensure_class_loaded( $self->model_adapter );
127 12         1165 $self->model_adapter(
128             $self->model_adapter->new(
129             { model_name => $self->model_name,
130             model_meta => $self->model_meta,
131             app_class => $app_class,
132             }
133             )
134             );
135             }
136             }
137              
138             =head2 do_model( I<context>, I<method>, I<args> )
139              
140             Checks for presence of model_adapter() instance and calls I<method> on either model()
141             or model_adapter() as appropriate.
142              
143             =cut
144              
145             sub do_model {
146 95     95 1 2101 my $self = shift;
147 95 50       273 my $c = shift or $self->throw_error("context required");
148 95 50       235 my $method = shift or $self->throw_error("method required");
149 95 100       298 if ( $self->model_adapter ) {
150 18         2435 return $self->model_adapter->$method( $self, $c, @_ );
151             }
152             else {
153 77         10187 return $c->model( $self->model_name )->$method(@_);
154             }
155             }
156              
157             =head2 model_can( I<context>, I<method_name> )
158              
159             Returns can() value from model_adapter() or model() as appropriate.
160              
161             =cut
162              
163             sub model_can {
164 13     13 1 39 my $self = shift;
165 13 50       36 my $c = shift or $self->throw_error("context required");
166 13 50       36 my $method = shift or $self->throw_error("method name required");
167 13 50       61 if ( $self->model_adapter ) {
168 0         0 return $self->model_adapter->can($method);
169             }
170             else {
171 13         1824 return $c->model( $self->model_name )->can($method);
172             }
173             }
174              
175             1;
176              
177             __END__
178              
179             =head1 AUTHOR
180              
181             Peter Karman, C<< <perl at peknet.com> >>
182              
183             =head1 BUGS
184              
185             Please report any bugs or feature requests to
186             C<bug-catalystx-crud at rt.cpan.org>, or through the web interface at
187             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CatalystX-CRUD>.
188             I will be notified, and then you'll automatically be notified of progress on
189             your bug as I make changes.
190              
191             =head1 SUPPORT
192              
193             You can find documentation for this module with the perldoc command.
194              
195             perldoc CatalystX::CRUD
196              
197             You can also look for information at:
198              
199             =over 4
200              
201             =item * Mailing List
202              
203             L<https://groups.google.com/forum/#!forum/catalystxcrud>
204              
205             =item * AnnoCPAN: Annotated CPAN documentation
206              
207             L<http://annocpan.org/dist/CatalystX-CRUD>
208              
209             =item * CPAN Ratings
210              
211             L<http://cpanratings.perl.org/d/CatalystX-CRUD>
212              
213             =item * RT: CPAN's request tracker
214              
215             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=CatalystX-CRUD>
216              
217             =item * Search CPAN
218              
219             L<http://search.cpan.org/dist/CatalystX-CRUD>
220              
221             =back
222              
223             =head1 ACKNOWLEDGEMENTS
224              
225             Thanks to Zbigniew Lukasiak and Matt Trout for feedback and API ideas.
226              
227             =head1 COPYRIGHT & LICENSE
228              
229             Copyright 2007 Peter Karman, all rights reserved.
230              
231             This program is free software; you can redistribute it and/or modify it
232             under the same terms as Perl itself.
233              
234             =cut