File Coverage

blib/lib/Dancer/Plugin/SimpleCRUD.pm
Criterion Covered Total %
statement 324 550 58.9
branch 108 240 45.0
condition 45 122 36.8
subroutine 29 35 82.8
pod n/a
total 506 947 53.4


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