File Coverage

blib/lib/Dancer/Plugin/SimpleCRUD.pm
Criterion Covered Total %
statement 317 540 58.7
branch 102 234 43.5
condition 42 114 36.8
subroutine 28 34 82.3
pod n/a
total 489 922 53.0


line stmt bran cond sub pod time code
1             # First, a dead simple object that can be fed a hashref of params from the
2             # Dancer params() keyword, and returns then when its param() method is called,
3             # so that we can feed it to CGI::FormBuilder:
4             package Dancer::Plugin::SimpleCRUD::ParamsObject;
5              
6             sub new {
7 0     0   0 my ($class, $params) = @_;
8 0         0 return bless { params => $params }, $class;
9             }
10              
11             sub param {
12 0     0   0 my ($self, @args) = @_;
13              
14             # If called with no args, return all param names
15 0 0       0 if (!@args) {
    0          
    0          
16 0 0       0 return $self->{params} if !$paramname;
17              
18             # With one arg, act as an accessor
19             } elsif (@args == 1) {
20 0         0 return $self->{params}{ $args[0] };
21              
22             # With two args, act as a mutator
23             } elsif ($args == 2) {
24 0         0 return $self->{params}{ $args[0] } = $args[1];
25             }
26             }
27              
28             # Now, on to the real stuff
29             package Dancer::Plugin::SimpleCRUD;
30              
31 3     3   366326 use warnings;
  3         7  
  3         85  
32 3     3   16 use strict;
  3         6  
  3         48  
33 3     3   743 use Dancer::Plugin;
  3         108605  
  3         176  
34 3     3   1066 use Dancer qw(:syntax);
  3         238247  
  3         15  
35 3     3   1539 use Dancer::Plugin::Database;
  3         36823  
  3         119  
36 3     3   1219 use HTML::Table::FromDatabase;
  3         47585  
  3         81  
37 3     3   1547 use CGI::FormBuilder;
  3         48083  
  3         123  
38 3     3   1139 use HTML::Entities;
  3         13800  
  3         218  
39 3     3   20 use URI::Escape;
  3         8  
  3         159  
40 3     3   1204 use List::MoreUtils qw( first_index uniq );
  3         18773  
  3         29  
41              
42             our $VERSION = '1.14';
43              
44             =encoding utf8
45              
46             =head1 NAME
47              
48             Dancer::Plugin::SimpleCRUD - very simple CRUD (create/read/update/delete)
49              
50              
51             =head1 DESCRIPTION
52              
53             A plugin for Dancer web applications, to use a few lines of code to create
54             appropriate routes to support creating/editing/deleting/viewing records within a
55             database table. Uses L to generate, process and validate forms,
56             L for database interaction and
57             L to display lists of records.
58              
59             Setting up forms and code to display and edit database records is a very common
60             requirement in web apps; this plugin tries to make something basic trivially
61             easy to set up and use.
62              
63              
64             =head1 SYNOPSIS
65              
66             The following assumes that you already have a working L app and have
67             put your database connection details in your C to be read by
68             L, which this plugin uses in order to obtain a database
69             connection.
70              
71             # In your Dancer app,
72             use Dancer::Plugin::SimpleCRUD;
73              
74             # Simple example:
75             simple_crud(
76             record_title => 'Widget',
77             prefix => '/widgets',
78             db_table => 'widgets',
79             editable => 1,
80             );
81              
82             # The above would create a route to handle C, listing all widgets,
83             # with options to add/edit entries (linking to C and
84             # C respectively) where a form to add a new entry or edit
85             # an existing entry will be created.
86             # All fields in the database table would be editable.
87             #
88             # There is also a view route, C, which shows all the values
89             # for the fields of a single database entry.
90              
91             # A more in-depth synopsis, using all options (of course, usually you'd only
92             # need to use a few of the options where you need to change the default
93             # behaviour):
94              
95             simple_crud(
96             record_title => 'Team',
97             prefix => '/teams',
98             db_table => 'team',
99             labels => { # More human-friendly labels for some columns
100             venue_id => 'Home Venue',
101             name => 'Team Name',
102             },
103             validation => { # validate values entered for some columns
104             division => qr/\d+/,
105             },
106             input_types => { # overriding form input type for some columns
107             supersecret => 'password',
108             lotsoftext' => 'textarea',
109             },
110             key_column => 'id', # id is default anyway
111             editable_columns => [ qw( venue_id name division ) ],
112             display_columns => [ qw( id venue_id name division ) ],
113             deleteable => 1,
114             editable => 1,
115             addable => 0, # does not allow adding rows
116             sortable => 1,
117             paginate => 300,
118             template => 'simple_crud.tt',
119             query_auto_focus => 1,
120             downloadable => 1,
121             foreign_keys => {
122             columnname => {
123             table => 'venues',
124             key_column => 'id',
125             label_column => 'name',
126             },
127             },
128             table_class => 'table table-bordered',
129             paginate_table_class => 'table table-borderless',
130             custom_columns => [
131             {
132             name => "division_news",
133             raw_column => "division",
134             transform => sub {
135             my $division_name = shift;
136             my $label = "News about $division_name";
137             $division_name =~ s/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
138             my $search = qq{http://news.google.com/news?q="$division_name"};
139             return "$label";
140             },
141             column_class => "column-class",
142             },
143             ],
144             auth => {
145             view => {
146             require_login => 1,
147             },
148             edit => {
149             require_role => 'Admin',
150             },
151             },
152             );
153              
154              
155              
156             =head1 USAGE
157              
158             This plugin provides a C keyword, which takes a hash of options as
159             described below, and sets up the appropriate routes to present add/edit/delete
160             options.
161              
162             =head1 OPTIONS
163              
164             The options you can pass to simple_crud are:
165              
166             =over 4
167              
168             =item C (required)
169              
170             What we're editing, for instance, if you're editing widgets, use 'Widget'. Will
171             be used in form titles (for instance "Add a ...", "Edit ..."), and button
172             labels.
173              
174             =item C (required)
175              
176             The prefix for the routes which will be created. Given a prefix of C,
177             then you can go to C to create a new Widget, and C to
178             edit the widget with the ID (see key_column) 42.
179              
180             Don't confuse this with Dancer's C setting, which would be prepended
181             before the prefix you pass to this plugin. For example, if you used:
182              
183             prefix '/foo';
184             simple_crud(
185             prefix => 'bar',
186             ...
187             );
188              
189             ... then you'd end up with e.g. C as the record listing page.
190              
191             =item C (required)
192              
193             The name of the database table.
194              
195             =item C (optional, default: 'id')
196              
197             Specify which column in the table is the primary key. If not given, defaults to
198             id.
199              
200             =item C (optional)
201              
202             Specify one or more 'where' clauses to use to filter the table. For example:
203              
204             simple_crud(
205             prefix => 'bar',
206             where_filter => {user_id => 1000},
207             ...
208             );
209              
210             This would cause only rows with an user_id of 1000 to be displayed in listings
211             and search results, viewed, edited etc.
212              
213             The C parameter takes a hashref describing the WHERE clause, as
214             used by L's C convenience method for
215             example - see the
216             L.
217              
218             Alternatively, if the filter condition needs to be calculated at runtime (for
219             example, based on the logged in user calling it), then you can provide a coderef
220             which returns the WHERE clause hashref - for instance:
221              
222             where_filter => sub { { customer_id => logged_in_user()->{customer_id} } },
223              
224             =item C (optional)
225              
226             We use L to obtain database connections. This option
227             allows you to specify the name of a connection defined in the config file to
228             use. See the documentation for L for how multiple
229             database configurations work. If this is not supplied or is empty, the default
230             database connection details in your config file will be used - this is often
231             what you want, so unless your app is dealing with multiple DBs, you probably
232             won't need to worry about this option.
233              
234             =item C (optional)
235              
236             A hashref of field_name => 'Label', if you want to provide more user-friendly
237             labels for some or all fields. As we're using CGI::FormBuilder, it will do a
238             reasonable job of figuring these out for itself usually anyway - for instance, a
239             field named C will be shown as C.
240              
241             =item C (optional)
242              
243             A hashref of field_name => input type, if you want to override the default type
244             of input which would be selected by L or by our DWIMmery (by
245             default, password fields will be used for field names like 'password', 'passwd'
246             etc, and text area inputs will be used for columns with type 'TEXT').
247              
248             Valid values include anything allowed by HTML, e.g. C, C
249             C