File Coverage

blib/lib/Catalyst/Plugin/AutoCRUD.pm
Criterion Covered Total %
statement 13 71 18.3
branch 0 20 0.0
condition 0 3 0.0
subroutine 5 7 71.4
pod n/a
total 18 101 17.8


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::AutoCRUD;
2             {
3             $Catalyst::Plugin::AutoCRUD::VERSION = '2.142820';
4             }
5              
6 1     1   15613 use strict;
  1         2  
  1         54  
7 1     1   4 use warnings FATAL => 'all';
  1         1  
  1         42  
8              
9 1     1   457 use MRO::Compat;
  1         2262  
  1         26  
10 1     1   420 use Devel::InnerPackage qw/list_packages/;
  1         2506  
  1         750  
11              
12             our $this_package = __PACKAGE__; # so it can be used in hash keys
13             our $VERSION ||= '0.00031412';
14              
15             sub setup_components {
16 0     0     my $class = shift;
17 0           $class->next::method(@_);
18              
19             # these are the boilerplate Catalyst components for AutoCRUD
20 0           my @packages = qw(
21             Controller::Root
22             Controller::Static
23             Controller::AJAX
24             Controller::DisplayEngine::ExtJS2
25             Controller::DisplayEngine::Skinny
26             Model::StorageEngine::DBIC
27             View::JSON
28             View::TT
29             );
30              
31             # will auto-load other models, so this one is not -required-
32 0 0         if (exists $class->config->{'Model::AutoCRUD::DBIC'}) {
33 0           push @packages, 'Model::DBIC';
34 0           my $p = 'Model::AutoCRUD::DBIC';
35              
36             # on the fly schema engineering
37 0 0         if (!exists $class->config->{$p}->{schema_class}) {
38 0           require DBIx::Class::Schema::Loader;
39 0 0         die "Must have DBIx::Class::Schema::Loader version > 0.04005"
40             if eval "$DBIx::Class::Schema::Loader::VERSION" <= 0.04005;
41              
42 0           DBIx::Class::Schema::Loader::make_schema_at(
43             'AutoCRUD::Loader::Schema', {naming => 'current'},
44             $class->config->{$p}->{connect_info},
45             );
46              
47 0           eval q{
48             package # hide from the PAUSE
49             AutoCRUD::Loader::Schema;
50             use base 'DBIx::Class::Schema';
51             AutoCRUD::Loader::Schema->load_classes();
52             1;
53             };
54 0           $INC{'AutoCRUD/Loader/Schema.pm'} = 'loaded';
55              
56 0           $class->config->{$p}->{schema_class} = 'AutoCRUD::Loader::Schema';
57             }
58             }
59              
60             # bodge the config for chained PathPart so the user can use our basepath
61             # shortcut in their config, which is less verbose than Cat's alternative
62 0           (my $config_key = $this_package) =~ s/^Catalyst:://;
63 0 0 0       if (exists $class->config->{$config_key}
64             and exists $class->config->{$config_key}->{basepath}) {
65 0           $class->config->{'Controller::AutoCRUD::Root'}->{action}->{base}->{PathPart}
66             = $class->config->{$config_key}->{basepath};
67             }
68              
69             # any additional backends requested
70 0 0         if (exists $class->config->{$config_key}->{backends}) {
71 0           my @backends = ref $class->config->{$config_key}->{backends} eq ref ''
72             ? $class->config->{$config_key}->{backends}
73 0 0         : @{ $class->config->{$config_key}->{backends} };
74              
75             # they will be componentized below
76 0           push @packages, map {'Model::StorageEngine::' . $_} @backends;
  0            
77              
78             # this so that they can be forwarded to in the controller
79 0           my %m = map {('Model::AutoCRUD::StorageEngine::' . $_) => 1} @backends;
  0            
80 0           ++$m{'Model::AutoCRUD::StorageEngine::DBIC'};
81 0           $class->config->{$config_key}->{backends} = [ keys %m ];
82             }
83             else {
84 0           $class->config->{$config_key}->{backends} =
85             [ 'Model::AutoCRUD::StorageEngine::DBIC' ];
86             }
87              
88 0           foreach my $orig (@packages) {
89 0           (my $p = $orig) =~ s/::/::AutoCRUD::/;
90 0           my $comp = "${class}::${p}";
91              
92             # require will shortcircuit and return true if the component is
93             # already loaded
94 0 0         unless (eval "package $class; require $comp;") {
95              
96             # make a component on the fly in the App namespace
97 0           eval qq(
98             package $comp;
99             use base qw/${this_package}::${orig}/;
100             1;
101             );
102 0 0         die $@ if $@;
103              
104             # inject entry to %INC so Perl knows this component is loaded
105             # this is just for politeness and does not aid Catalyst
106 0           (my $file = "$comp.pm") =~ s{::}{/}g;
107 0           $INC{$file} = 'loaded';
108              
109             # add newly created components to catalyst
110             # must set up component and -then- call list_packages on it
111 0           $class->components->{$comp} = $class->setup_component($comp);
112 0           for my $m (list_packages($comp)) {
113 0           $class->components->{$m} = $class->setup_component($m);
114             }
115             }
116             }
117              
118 0           return 1;
119             }
120              
121             # we subvert the pretty print error screen for dumpmeta
122             sub dump_these {
123 0     0     my $c = shift;
124              
125 0           my $params = {
126 0           map {$_ => $c->stash->{$_}}
127 0           grep {ref $c->stash->{$_} eq ''}
128 0           grep {$_ =~ m/^cpac_/}
129 0           keys %{$c->stash},
130             };
131              
132             # strip the SQLT objects
133 0           my $meta = undef;
134 0 0         if (exists $c->stash->{cpac}->{m}) {
135 0           $meta = scalar $c->stash->{cpac}->{m}->extra;
136 0           foreach my $t (values %{$c->stash->{cpac}->{m}->t}) {
  0            
137 0           $meta->{t}->{$t->name} = scalar $t->extra;
138 0           foreach my $f (values %{$t->f}) {
  0            
139 0           $meta->{t}->{$t->name}->{f}->{$f->name} = scalar $f->extra;
140             }
141             }
142             }
143              
144 0 0         if ($c->stash->{dumpmeta}) {
145             return (
146 0           [ 'CPAC Parameters (cpac_*)' => $params ],
147             [ 'Global Configuration (g)' => $c->stash->{cpac}->{g} ],
148             [ 'Site Configuration (c)' => $c->stash->{cpac}->{c} ],
149             [ 'Storage Metadata (m)' => $meta ],
150             [ 'Response' => $c->response ], # only to pacify log_request
151             );
152             }
153 0           else { $c->next::method(@_) }
154             }
155              
156             # monkey patch Catalyst::View::JSON until it is fixed, or users will get scared
157             # by the warning currently emitted by Catalyst
158              
159 1     1   213 use Catalyst::View::JSON;
  0            
  0            
160             my $json_new = _get_subref('new', 'Catalyst::View::JSON');
161             {
162             no warnings 'redefine';
163             *Catalyst::View::JSON::new = sub {
164             delete $_[2]->{catalyst_component_name};
165             goto $json_new;
166             };
167             }
168              
169             sub _get_subref {
170             my $sub = shift;
171             my $pkg = shift || scalar caller(0);
172              
173             my $symtbl = \%{main::};
174             foreach my $part(split /::/, $pkg) {
175             $symtbl = $symtbl->{"${part}::"};
176             }
177              
178             return eval{ \&{ $symtbl->{$sub} } };
179             }
180              
181             1;
182              
183             # ABSTRACT: Instant AJAX web front-end for DBIx::Class
184              
185              
186             __END__
187             =pod
188              
189             =head1 NAME
190              
191             Catalyst::Plugin::AutoCRUD - Instant AJAX web front-end for DBIx::Class
192              
193             =head1 VERSION
194              
195             version 2.142820
196              
197             =head1 PURPOSE
198              
199             You have a database, and wish to have a basic web interface supporting Create,
200             Retrieve, Update, Delete and Search, with little effort. This module is able
201             to create such interfaces on the fly. They are a bit whizzy and all Web
202             2.0-ish.
203              
204             =over 4
205              
206             =item *
207              
208             See the demo at: L<http://demo.autocrud.pl/>
209              
210             =back
211              
212             =head1 SYNOPSIS
213              
214             If you already have a L<Catalyst> app with L<DBIx::Class> models configured:
215              
216             use Catalyst qw(AutoCRUD); # <-- add the plugin name here in MyApp.pm
217              
218             Now load your app in a web browser, but add C</autocrud> to the URL path.
219              
220             Alternatively, to connect to an external database if you have the DBIX::Class
221             schema available, use the C<ConfigLoader> plugin with the following config:
222              
223             <Model::AutoCRUD::DBIC>
224             schema_class My::Database::Schema
225             connect_info dbi:Pg:dbname=mydbname;host=mydbhost.example.com;
226             connect_info username
227             connect_info password
228             <connect_info>
229             AutoCommit 1
230             </connect_info>
231             </Model::AutoCRUD::DBIC>
232              
233             If you don't have the DBIx::Class schema available, just omit the
234             C<schema_class> option (and have L<DBIx::Class::Schema::Loader> installed).
235              
236             =head1 DESCRIPTION
237              
238             This module contains an application which will automatically construct a web
239             interface for a database on the fly. The web interface supports Create,
240             Retrieve, Update, Delete and Search operations.
241              
242             The interface is not written to static files on your system, and uses AJAX to
243             act upon the database without reloading your web page (much like other
244             Web 2.0 applications, for example Google Mail).
245              
246             Almost all the information required by the plugin is retrieved from the
247             L<DBIx::Class> ORM frontend to your database, which it is expected that you
248             have already set up (although see L</USAGE>, below). This means that any
249             change in database schema ought to be reflected immediately in the web
250             interface after a page refresh.
251              
252             =head1 USAGE
253              
254             =head2 Read Me First
255              
256             =over 4
257              
258             =item *
259              
260             If you get stuck, read the
261             L<Troubleshooting|Catalyst::Plugin::AutoCRUD::Manual::Troubleshooting> documentation.
262              
263             =item *
264              
265             L<DBIx::Class> users should read
266             L<DBIx::Class Tips|Catalyst::Plugin::AutoCRUD::Manual::DBICTips>.
267              
268             =item *
269              
270             This plugin provides no user-based access authentication or authorization.
271             Please take care when deploying, and consider who will have access. It is
272             possible to restrict the add/update/delete operations on data. See L</TIPS
273             AND TRICKS> for other suggestions.
274              
275             =back
276              
277             =head2 Scenario 1: Plugin to an existing Catalyst App
278              
279             This mode is for when you have written your Catalyst application, but the
280             Views are catering for the users and as an admin you'd like a more direct,
281             secondary web interface to the database.
282              
283             package AutoCRUDUser;
284             use Catalyst qw(AutoCRUD);
285            
286             __PACKAGE__->setup;
287             1;
288              
289             Adding C<Catalyst::Plugin::AutoCRUD> as a plugin to your Catalyst application,
290             as above, causes it to scan your existing Models. If any of them are built
291             using L<Catalyst::Model::DBIC::Schema>, they are automatically loaded.
292              
293             This mode of operation works even if you have more than one database. You will
294             be offered a Home screen to select the database, and then another menu to
295             select the table within that.
296              
297             Remember that the pages available from this plugin will be located under the
298             C</autocrud> path of your application. Use the C<basepath> option if you want
299             to override this.
300              
301             =head2 Scenario 2: Frontend for an existing C<DBIx::Class::Schema> based class
302              
303             In this mode, C<Catalyst::Plugin::AutoCRUD> is running standalone, in a sense
304             as the Catalyst application itself. Your main application file looks almost
305             the same as in Scenario 1, except you'll need the C<ConfigLoader> plugin:
306              
307             package AutoCRUDUser;
308             use Catalyst qw(ConfigLoader AutoCRUD);
309            
310             __PACKAGE__->setup;
311             1;
312              
313             For the configuration, you need to tell AutoCRUD which package contains the
314             C<DBIx::Class> schema, and also provide database connection parameters.
315              
316             <Model::AutoCRUD::DBIC>
317             schema_class My::Database::Schema
318             connect_info dbi:Pg:dbname=mydbname;host=mydbhost.example.com;
319             connect_info username
320             connect_info password
321             <connect_info>
322             AutoCommit 1
323             </connect_info>
324             </Model::AutoCRUD::DBIC>
325              
326             The C<Model::AutoCRUD::DBIC> section must look (and be named) exactly like that
327             above, except you should of course change the C<schema_class> value and the
328             values within C<connect_info>.
329              
330             Remember that the pages available from this plugin will be located under the
331             C</autocrud> path if your application. Use the C<basepath> option if you want
332             to override this.
333              
334             =head3 C<DBIx::Class> setup
335              
336             You will of course need the C<DBIx::Class> schema to be created and installed
337             on your system. The recommended way to do this quickly is to use the excellent
338             L<DBIx::Class::Schema::Loader> module which connects to your database and
339             writes C<DBIx::Class> Perl modules for it.
340              
341             Pick a suitable namespace for your schema, which is not related to this
342             application. For example C<DBIC::Database::Foo::Schema> for the C<Foo>
343             database (in the configuration example above we used C<My::Database::Schema>).
344             Then use the following command-line incantation:
345              
346             perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:. -e \
347             'make_schema_at("DBIC::Database::Foo::Schema", { debug => 1, naming => 'current' }, \
348             ["dbi:Pg:dbname=foodb;host=mydbhost.example.com","user","pass" ])'
349              
350             This will create a directory (such as C<DBIC>) which you need to move into
351             your Perl Include path (one of the paths shown at the end of C<perl -V>).
352              
353             =head2 Scenario 3: Lazy loading a C<DBIx::Class> schema
354              
355             If you're in such a hurry that you can't create the C<DBIx::Class> schema, as
356             shown in the previous section, then C<Catalyst::Plugin::AutoCRUD> is able to
357             do this on the fly, but it will slow the application's startup just a little.
358              
359             The application file and configuration are very similar to those in Scenario
360             two, above, except that you omit the C<schema_class> configuration option
361             because you want AutoCRUD to generate that on the fly (rather than reading an
362             existing one from disk).
363              
364             package AutoCRUDUser;
365             use Catalyst qw(ConfigLoader AutoCRUD);
366            
367             __PACKAGE__->setup;
368             1;
369              
370             <Model::AutoCRUD::DBIC>
371             connect_info dbi:Pg:dbname=mydbname;host=mydbhost.example.com;
372             connect_info username
373             connect_info password
374             <connect_info>
375             AutoCommit 1
376             </connect_info>
377             </Model::AutoCRUD::DBIC>
378              
379             When AutoCRUD loads it will connect to the database and use the
380             L<DBIx::Class::Schema::Loader> module to reverse engineer its schema. To work
381             properly you'll need the very latest version of that module (at least 0.05,
382             or the most recent development release from CPAN).
383              
384             The other drawback to this scenario (other than the slower operation) is that
385             you have no ability to customize how foreign, related records are shown. A
386             related record will simply be represented as something approximating the name
387             of the foreign table, the names of the primary keys, and associated values
388             (e.g. C<id(5)>).
389              
390             =head1 TIPS AND TRICKS
391              
392             =head2 Displaying Unicode
393              
394             It is essential that you load the L<Catalyst::Plugin::Unicode::Encoding>
395             plugin to ensure proper decoding/encoding of incoming request parameters and
396             the outgoing body response respectively. This is done in your C<MyApp.pm>:
397              
398             use Catalyst qw/ -Debug ConfigLoader Unicode::Encoding AutoCRUD /;
399              
400             Additionally, when connecting to the database, add a flag to the connection
401             parameters, specific to your database engine, that enables Unicode. See the
402             following link for more details:
403              
404             =over 4
405              
406             =item *
407              
408             L<https://metacpan.org/module/DBIx::Class::Manual::Cookbook#Using-Unicode>
409              
410             =back
411              
412             =head2 Representing related records
413              
414             When the web interface wants to display a column which references another
415             table, you can make things look much better by adding a custom render method
416             to your C<DBIx::Class> Result Classes (i.e. the class files for each table).
417              
418             First, the plugin will look for a method called C<display_name> and use that.
419             Here is an example which could be added to your Result Class files below the
420             line which reads C<DO NOT MODIFY THIS OR ANYTHING ABOVE>, and in this case
421             returns the data from the C<title> column:
422              
423             sub display_name {
424             my $self = shift;
425             return $self->title || '';
426             }
427              
428             Failing the existence of a C<display_name> method, the plugin attempts to
429             stringify the row object. Using stringification is not recommended, although
430             some people like it. Here is an example of a stringification handler:
431              
432             use overload '""' => sub {
433             my $self = shift;
434             return $self->title || '';
435             }, fallback => 1;
436              
437             If all else fails the plugin prints the best hint it can to describe the
438             foreign row. This is something approximating the name of the foreign table,
439             the names of the primary keys, and associated values. It's better than
440             stringifying the object the way Perl does, anyway.
441              
442             =head2 Textfields and Textareas
443              
444             When the plugin creates a web form for adding or editing, it has to choose
445             whether to show a Textfield or Textarea for text-type fields. If you have set
446             a C<size> option in add_columns() within the Schema, and this is less than or
447             equal to 40, a Textfield is used. Otherwise, if the C<size> option is larger
448             than 40 or not set, then an auto-expanding, scrollable Textarea is used.
449              
450             =head2 Column names with spaces
451              
452             The plugin will handle most tricky names, but you should remember to pass some
453             required extra quoting hints to DBIx::Class when it makes a connection to your
454             database:
455              
456             # most databases:
457             { quote_char => q{`}, name_sep => q{.} }
458            
459             # SQL Server:
460             { quote_char => [qw/[ ]/], name_sep => q{.} }
461              
462             For more information see the L<DBIx::Class::Storage::DBI> manual page or ask
463             on the DBIx::Class mail list.
464              
465             =head2 Database IO filters
466              
467             Buried within one of the modules in this application are some filters which
468             are applied to data of certain types as it enters or leaves the database. If
469             you find a particular data type is not being rendered correctly, please drop
470             the author a line at the email address below, explaining what you'd like to
471             see instead.
472              
473             =head2 Relocating AutoCRUD to another URL path
474              
475             If you want to use this application as a plugin with another Catalyst system,
476             it should work fine, but you probably want to serve pages under a different
477             path on your web site. To that end, the plugin by default places its pages
478             under a path part of C<...E<sol>autocrudE<sol>>. You can change this by adding
479             the following option to your configuration file:
480              
481             <Plugin::AutoCRUD>
482             basepath admin
483             </Plugin::AutoCRUD>
484              
485             In the above example, the path C<...E<sol>adminE<sol>> will contain the AutoCRUD
486             application, and all generated links in AutoCRUD will also make use of that path.
487             Remember this is added to the C<base> of your Cataylst application which,
488             depending on your web server configuration, might also have a leading path.
489              
490             To have the links based at the root of your application (which was the default
491             behaviour of C<CatalystX::ListFramework::Builder>, set this variable to an
492             empty string in your configuration:
493              
494             <Plugin::AutoCRUD>
495             basepath ""
496             </Plugin::AutoCRUD>
497              
498             =head2 Using your own ExtJS libraries
499              
500             The plugin will use copies of the ExtJS libraries hosted in the CacheFly
501             content delivery network out there on the Internet. Under some circumstances
502             you'll want to use your own hosted copy, for instance if you are serving HTTPS
503             (because browsers will warn about mixed HTTP and HTTPS content).
504              
505             In which case, you'll need to download the ExtJS Javascript Library (version
506             2.2+ recommended), from this web page:
507             L<http://www.sencha.com/products/extjs/download/>.
508              
509             Install it to your web server in a location that it is able to serve as static
510             content. Make a note of the path used in a URL to retrieve this content, as it
511             will be needed in the application configuration file, like so:
512              
513             <Plugin::AutoCRUD>
514             extjs2 /static/javascript/extjs-2
515             </Plugin::AutoCRUD>
516              
517             Use the C<extjs2> option as shown above to specify the URL path to the
518             libraries. This will be used in the templates in some way like this:
519              
520             <script type="text/javascript" src="[% c.config.extjs2 %]/ext-all.js" />
521              
522             =head2 Changing the HTML Character Set
523              
524             The default HTML C<charset> used by this module is C<utf-8>. If you wish to override
525             this, then set the C<html_charset> parameter, as below:
526              
527             <Plugin::AutoCRUD>
528             html_charset iso-8859-1
529             </Plugin::AutoCRUD>
530              
531             =head2 Simple read-only non-JavaScript Frontend
532              
533             All table views will default to the full-featured ExtJS based frontend. If you
534             would prefer to see a simple read-only non-JavaScript interface, then append
535             C</browse> to your URL.
536              
537             This simpler frontend uses HTTP GET only, supports paging and sorting, and
538             will obey any column filtering and renaming as set in your L</"SITES CONFIGURATION"> file.
539              
540             =head2 Overriding built-in Templates
541              
542             The whole site is built from Perl Template Toolkit templates, and it is
543             possible to override these shipped templates with your own files. This goes
544             for both general files (CSS, top-level TT wrapper) as well as the site files
545             mentioned in the next section.
546              
547             To add these override paths, include the following directive in your
548             configuration file:
549              
550             <Plugin::AutoCRUD>
551             tt_path /path/to/my/local/templates
552             </Plugin::AutoCRUD>
553              
554             This C<tt_path> directive can be included multiple times to set a list of
555             override paths, which will be processed in the order given.
556              
557             Within the specified directory you should mirror the file structure where the
558             overridden templates have come from, including the frontend name. For example:
559              
560             extjs2
561             extjs2/wrapper
562             extjs2/wrapper/footer.tt
563             skinny
564             skinny/wrapper
565             skinny/wrapper/footer.tt
566              
567             If you want to override any of the CSS used in the app, copy the C<head.tt>
568             template from whichever C<site> you are using, edit, and install in a local
569             C<tt_path> set with this directive.
570              
571             =head2 Reconfiguring Embedded Plugins
572              
573             Embedded plugins such as L<Catalyst::View:TT>, L<Catalyst::View::JSON>, etc,
574             can be reconfigured in your C<myapp.yml> file using a simple naming
575             convention. Remove the leading "Catalyst", and insert "AutoCRUD" after the
576             first namespace component. For example:
577              
578             View::AutoCRUD::TT:
579             ENCODING: utf-8
580              
581             Note that this does not affect your own App's usage of the same plugins, only
582             the AutoCRUD plugin's instances are reconfigured.
583              
584             =head1 SITES CONFIGURATION
585              
586             It's possible to have multiple views of the source data, tailored in various
587             ways. For example you might choose to hide some tables, or columns within
588             tables, rename headings of columns, or disable updates or deletes.
589              
590             This is all achieved through the C<sites> configuration. Altering the default
591             site simply allows for control of column naming, hiding, etc. Creating a new
592             site allows you to present alternate configurations of the same source data.
593              
594             =head2 Altering the Default Site
595              
596             When using this plugin out of the box you're already running within the
597             default site, which unsurprisingly is called C<default>. To override settings
598             in this, create the following configuration stub, and fill it in with any of
599             the options listed below:
600              
601             <Plugin::AutoCRUD>
602             <sites>
603             <default>
604             # override settings here
605             </default>
606             </sites>
607             </Plugin::AutoCRUD>
608              
609             =head2 Configuration Options for Sites
610              
611             In general, when you apply a setting to something at a higher level (say, a
612             database), it I<percolates> down to the child sections (i.e. the tables). For
613             example, setting C<delete_allowed no> on a database will prevent records from
614             any table within that from being deleted.
615              
616             Some of the options are I<global> for a site, others apply to the database or
617             table within it. To specify an option for one or the other, use the database
618             and table names I<as they appear in the URL path>:
619              
620             <Plugin::AutoCRUD>
621             <sites>
622             <default>
623             # global settings for the site, here
624             <mydb>
625             # override settings here
626             <sometable>
627             # and/or override settings here
628             </sometable
629             </mydb>
630             </default>
631             </sites>
632             </Plugin::AutoCRUD>
633              
634             =head3 Options
635              
636             =over 4
637              
638             =item update_allowed [ yes* | no ]
639              
640             This can be applied to either a database or a table; if applied to a database it
641             percolates to all the tables, unless the table has a different setting.
642              
643             The default is to allow updates to be made to existing records. Set this to a
644             value of C<no> to prevent this operation from being permitted. Widgets will
645             also be removed from the user interface so as not to confuse users.
646              
647             <Plugin::AutoCRUD>
648             <sites>
649             <default>
650             update_allowed no
651             </default>
652             </sites>
653             </Plugin::AutoCRUD>
654              
655             =item create_allowed [ yes* | no ]
656              
657             This can be applied to either a database or a table; if applied to a database it
658             percolates to all the tables, unless the table has a different setting.
659              
660             The default is to allow new records to be created. Set this to a value of
661             C<no> to prevent this operation from being allowed. Widgets will also be
662             removed from the user interface so as not to confuse users.
663              
664             <Plugin::AutoCRUD>
665             <sites>
666             <default>
667             create_allowed no
668             </default>
669             </sites>
670             </Plugin::AutoCRUD>
671              
672             =item delete_allowed [ yes* | no ]
673              
674             This can be applied to either a database or a table; if applied to a database it
675             percolates to all the tables, unless the table has a different setting.
676              
677             The default is to allow deletions of records in the tables. Set this to a
678             value of C<no> to prevent deletions from being allowed. Widgets will also be
679             removed from the user interface so as not to confuse users.
680              
681             <Plugin::AutoCRUD>
682             <sites>
683             <default>
684             delete_allowed no
685             </default>
686             </sites>
687             </Plugin::AutoCRUD>
688              
689             =item columns \@column_names
690              
691             This option achieves two purposes. First, you can re-order the set of columns
692             as they are displayed to the user. Second, by omitting columns from this list
693             you can hide them from the main table views.
694              
695             Provide a list of the column names (as the data source knows them) to this
696             setting. This option must appear at the table level of your site config
697             hierarchy. In C<Config::General> format, this would look something like:
698              
699             <Plugin::AutoCRUD>
700             <sites>
701             <default>
702             <mydb>
703             <thetable>
704             columns id
705             columns title
706             columns length
707             </thetable>
708             </mydb>
709             </default>
710             </sites>
711             </Plugin::AutoCRUD>
712              
713             Any columns existing in the table, but not mentioned there, will not be
714             displayed in the main table. They'll still appear in the record edit form, as
715             some fields are required by the database schema so cannot be hidden. Columns
716             will be displayed in the same order that you list them in the configuration.
717              
718             =item headings { col => title, ... }
719              
720             You can alter the title given to any column in the user interface, by
721             providing a hash mapping of column names (as the data source knows them) to
722             titles you wish displayed to the user. This option must appear at the table
723             level of your site config hierarchy. In C<Config::General> format, this would
724             look something like:
725              
726             <Plugin::AutoCRUD>
727             <sites>
728             <default>
729             <mydb>
730             <thetable>
731             <headings>
732             id Key
733             title Name
734             length Time
735             </headings>
736             </thetable>
737             </mydb>
738             </default>
739             </sites>
740             </Plugin::AutoCRUD>
741              
742             Any columns not included in the hash mapping will use the default title (i.e.
743             what the plugin works out for itself). To hide a column from view, use the
744             C<columns> option, described above.
745              
746             =item hidden [ yes | no* ]
747              
748             If you don't want a database to be offered to the user, or likewise a particular
749             table, then set this option to C<yes>. By default, all databases and tables are
750             shown in the user interface.
751              
752             <Plugin::AutoCRUD>
753             <sites>
754             <default>
755             <mydb>
756             <secrettable>
757             hidden yes
758             </secrettable>
759             </mydb>
760             </default>
761             </sites>
762             </Plugin::AutoCRUD>
763              
764             This can be applied to either a database or table; if applied to a database it
765             overrides all child tables, B<even if> a table has a different setting.
766              
767             =item frontend [ extjs2 | skinny | ... ]
768              
769             With this option you can swap out the set of templates used to generate the
770             web front-end, and completely change its look and feel.
771              
772             Currently you have two choices: either C<extjs2> which is the default and
773             provides the standard full-featured ExtJS2 frontend, or C<skinny> which is a
774             read-only non-JavaScript alternative supporting listing, paging and sorting
775             only.
776              
777             Set the frontend in your site config at its top level. Note that you cannot
778             set the frontend on a per-database or per-table basis, only per-site:
779              
780             <Plugin::AutoCRUD>
781             <sites>
782             <default>
783             frontend skinny
784             </default>
785             </sites>
786             </Plugin::AutoCRUD>
787              
788             Be aware that setting the frontend to C<skinny> does B<not> restrict create or
789             update access to your database via the AJAX API. For that, you still should
790             set the C<*_allowed> options listed above, as required.
791              
792             =back
793              
794             =head2 Creating a New Site
795              
796             You can create a new site by adding it to the C<sites> section of your
797             configuration:
798              
799             <Plugin::AutoCRUD>
800             <sites>
801             <mysite>
802             # local settings here
803             </mysite>
804             </sites>
805             </Plugin::AutoCRUD>
806              
807             You'll notice that a non-default site is active because the path in your URLs
808             changes to a more RPC-like verbose form, mentioning the site, database and
809             table:
810              
811             from this:
812             .../autocrud/mydb/thetable # (i.e. site == default)
813            
814             to this:
815             .../autocrud/site/mysite/schema/mydb/source/thetable
816              
817             So let's say you've created a dumbed down site for your users which is
818             read-only (i.e. C<update_allowed no> and C<delete_allowed no>), and called the
819             site C<simplesite> in your configuration. You need to give the following URL
820             to users:
821              
822             .../autocrud/site/simplesite
823              
824             You could also then place an access control on this path part in your web
825             server (e.g. Apache) which is different from the default site itself.
826              
827             =head1 INSTANT DEMO APPLICATIONS
828              
829             =head2 Automagic Loading
830              
831             If you want to run an instant demo of this module, with minimal configuration,
832             then a simple application for that is shipped with this distribution. For this
833             to work, you must have:
834              
835             =over 4
836              
837             =item *
838              
839             The very latest version of L<DBIx::Class::Schema::Loader> installed on your
840             system (at least 0.05, or the most recent release from CPAN).
841              
842             =item *
843              
844             SQLite3 and the accompanying DBD module, if you want to use the shipped demo
845             database.
846              
847             =back
848              
849             Go to the C<examples/sql/> directory of this distribution and run the
850             C<bootstrap_sqlite.pl> perl script. This will create an SQLite file.
851              
852             Now change to the C<examples/demo/> directory and start the demo application
853             like so:
854              
855             demo> perl ./server.pl
856              
857             Visit C<http://localhost:3000> in your browser as instructed at the end of
858             the output from this command.
859              
860             To use your own database rather than the SQLite demo, edit
861             C<examples/demo/demo.conf> so that it contains the correct C<dsn>, username,
862             and password for your database. Upon restarting the application you should see
863             your own data source instead.
864              
865             =head2 Row Display Names
866              
867             An alternate application exists which demonstrates use of the C<display_name>
868             method on a L<DBIx::Class> Row, to give row entries "friendly names". Follow
869             all the instructions above but instead run the following server script:
870              
871             demo> perl ./server_with_display_name.pl
872              
873             =head2 Other Features
874              
875             Finally, the kitchen sink of other features supported by this module are
876             demonstrated in a separate application. This contains many tables, each of
877             which highlights one or more aspects of a relational database backend being
878             rendered in AutoCRUD.
879              
880             Follow all the instructions above, but instead run the following server
881             script:
882              
883             demo> perl ./server_other_features.pl
884              
885             =head1 TROUBLESHOOTING
886              
887             See L<Catalyst::Plugin::AutoCRUD::Manual::Troubleshooting>.
888              
889             =head1 LIMITATIONS
890              
891             See L<Catalyst::Plugin::AutoCRUD::Manual::Limitations>.
892              
893             =head1 SEE ALSO
894              
895             L<CatalystX::CRUD> and L<CatalystX::CRUD:YUI> are two distributions which
896             allow you to create something similar but with full customization, and the
897             ability to add more features. So, you trade effort for flexibility and power.
898              
899             =head1 ACKNOWLEDGEMENTS
900              
901             Without the initial work on C<CatalystX::ListFramework> by Andrew Payne and
902             Peter Edwards this package would not exist. If you are looking for something
903             like this module but without the dependency on Javascript, please do check
904             out L<CatalystX::ListFramework>.
905              
906             =head1 AUTHOR
907              
908             Oliver Gorwits <oliver@cpan.org>
909              
910             =head1 COPYRIGHT AND LICENSE
911              
912             This software is copyright (c) 2014 by Oliver Gorwits.
913              
914             This is free software; you can redistribute it and/or modify it under
915             the same terms as the Perl 5 programming language system itself.
916              
917             =cut
918