File Coverage

blib/lib/CGI/Application/Structured.pm
Criterion Covered Total %
statement 49 51 96.0
branch n/a
condition n/a
subroutine 17 17 100.0
pod n/a
total 66 68 97.0


line stmt bran cond sub pod time code
1             package CGI::Application::Structured;
2 1     1   26072 use strict;
  1         3  
  1         37  
3 1     1   5 use warnings;
  1         2  
  1         30  
4 1     1   5 use base 'CGI::Application';
  1         7  
  1         1389  
5              
6 1     1   9524 use vars qw($VERSION);
  1         3  
  1         60  
7             $VERSION = '0.007';
8              
9              
10             # Load recommended plugins by default.
11 1     1   1113 use CGI::Application::Plugin::Forward;
  1         599  
  1         51  
12 1     1   1094 use CGI::Application::Plugin::Redirect;
  1         247  
  1         6  
13 1     1   1283 use CGI::Application::Plugin::Session;
  1         9996  
  1         8  
14 1     1   1293 use CGI::Application::Plugin::ValidateRM;
  1         62203  
  1         148  
15 1     1   1097 use CGI::Application::Plugin::ConfigAuto 'cfg';
  1         962  
  1         6  
16 1     1   1087 use CGI::Application::Plugin::FillInForm 'fill_form';
  1         790  
  1         77  
17 1     1   1293 use CGI::Application::Plugin::DBH qw(dbh_config dbh);
  1         2051  
  1         72  
18 1     1   1018 use CGI::Application::Plugin::LogDispatch;
  1         36641  
  1         8  
19 1     1   935 use CGI::Application::Plugin::TT;
  1         34624  
  1         10  
20 1     1   1250 use CGI::Application::Plugin::AutoRunmode;
  1         19010  
  1         11  
21 1     1   1634 use CGI::Application::Plugin::SuperForm;
  1         8407  
  1         133  
22 1     1   1080 use CGI::Application::Plugin::DBIC::Schema qw/dbic_config schema resultset/;
  1         987  
  1         85  
23 1     1   543 use CGI::Application::Plugin::DebugScreen;
  0            
  0            
24              
25              
26             #################### main pod documentation begin ###################
27              
28             =head1 NAME
29              
30             CGI::Application::Structured - A medium-weight, MVC, DB web micro-framework.
31              
32             =head2 SYNOPSIS
33              
34             A simple, medium-weight, MVC, DB web micro-framework built on CGI::Application. The framework combines tested, well known plugins and helper scripts to provide a rapid development environment.
35              
36             The bundled plugins mix the following methods into your controller runmodes:
37              
38             $c->forward(runmode)
39              
40             $c->redirect(url)
41              
42             $c->tt_param(name=>value)
43              
44             $c->tt_process()
45              
46             $c->schema()->resultset("Things")->find($id)
47              
48             $c->resultset("Things)->search({color=>"red"})
49              
50             $c->log->info('This also works')
51              
52             my $value = $c->session->param('key')
53              
54             my $conf_val = $c->cfg('field');
55              
56             my $select = $c->superform->select(
57             name => 'select',
58             default => 2,
59             values => [ 0, 1, 2, 3 ],
60             labels => {
61             0 => 'Zero',
62             1 => 'One',
63             2 => 'Two',
64             3 => 'Three'
65             }
66             );
67              
68              
69             sub method: Runmode {my $c = shift; do_something();}
70              
71             $c->fill_form( \$template )
72              
73             my $results = $ ->check_rm(
74             'form_display','_form_profile')
75             || return $c->check_rm_error_page;
76              
77              
78              
79             =head1 DESCRIPTION
80              
81              
82             I have taken to heart a recent comment by Mark Stosberg on the CGIApp mailing list:
83              
84             =over 8
85              
86             "Titanium is just one vision of what can be built on top of
87             CGI::Application. Someone else could easily combine their own
88             combination of CGI::Application and different favorite plugins,
89             and publish that with a different name."
90              
91             =back
92              
93             CGI::Application::Structured, like L, is an opinionated framework, based on CGI::Application. Both frameworks includes a number of vetted CGI-App plugins each of which are well documented and tested. C::A::Structured, however takes the view that developer time and consistent projects structures can often be more cost-effective than focusing on the highest performance on low cost hosting solutions. That being said, C::A::Structured can be deployed on CGI, FastCGI or mod_perl based on your needs.
94              
95             C::A::Structured focuses on:
96              
97             =over 4
98              
99             =item *
100              
101             adequate performance under CGI, but with more focus speed of development.
102              
103             =item *
104              
105             a well-defined project structure with directories for model classes, controllers and view templates.
106              
107             =item *
108              
109             a powerful templating DSL via Template Toolkit integration.
110              
111             =item *
112              
113             a integrated Object Relational Mapper, L
114              
115             =item *
116              
117             no runmode configuration required.
118              
119             =item *
120              
121             integrated form building to simplify creation of complex HTML form elements.
122              
123             =item *
124              
125             clean url-to-controller mapping by default.
126              
127              
128             =back
129              
130             C::A::Structured comes in two packages:
131              
132             =over 4
133              
134             =item *
135              
136             CGI::Application::Strutured - encapsulates the runtime environment.
137              
138             =item *
139              
140             CGI::Application::Structured::Tools - includes project creation and developemt scripts for developers.
141              
142             =back
143              
144             CGI::Application::Structured::Tools are used to generate a micro-architecture and helper scripts that work within that structure to speed development and maintain project structure across development teams and projects. The helper scripts eliminate the tedium of error-prone manual creation of controllers, templates and database mappings and provide a recognizeable structural conventions that reduced stress on the developer when working across multiple apps, or working with other developers code on the same project.
145              
146             The first script that is used is 'cas-starter.pl'. This script is used to generate the initial project skeleton. The skeleton app contains a base controller class rather than runnable module as would be found in L. Also generated is a default 'Home' controller subclass and a URL dispatcher that is customized to default to the Home controllers generated 'index' runmode.
147              
148             cas-starter.pl also generates additional helper scripts in your projects 'scripts' subdirectory:
149              
150             =over 4
151              
152             =item *
153              
154             create_controller.pl
155              
156             =item *
157              
158             create_dbic_schema.pl
159              
160             =back
161              
162             'create_controller.pl' is used by the developer to generate additional controller subclasses of your base module with a default 'index' runmode and a default TT template for that runmode.
163              
164             'create_dbic_schema.pl' generates a DBIx::Class::Schema subclass and a set of resultset subclasses for your database. These Object Relational Maps (ORM) will greatly simplify and speed database assess and manipulation in the development process.
165              
166             Finally CGI::Application::Structured aims to be as compatible as possible with L. Many plugins used in CGI::Application::Structured are also available for Catalyst, or are even defaults in L. If your projects needs grow in scope or scale to require Catalyst, porting much of your code will be very easy.
167              
168              
169             =head1 CGI::Application::Structured Tutorial
170              
171              
172              
173             In this tutorial we will build a simplistic database driven web application using CGI::Application::Structured to demonstrate using the starter and helper scripts as well as the minimal required configuration.
174              
175             CGI::Application::Structured assumes that you have a database that you want to use with the web. If you have a database you can use for this tutorial. Otherwise, jump to the "Create The Example Database" section at the bottom of this page before starting the tutorial.
176              
177              
178             =cut
179              
180             =head2 Installation
181              
182             You will need to install L which provides the runtime requirements. You will also need to install L which supplies the development environment.
183              
184             ~/dev$ sudo cpan
185             cpan> install CGI::Application::Structured
186             ... ok
187             cpan> install CGI::Application::Structured::Tools
188             ... ok
189             cpan> exit
190              
191              
192             =cut
193              
194             =head2 Creating A Project
195              
196              
197             ~/dev$ cas-starter.pl --module=MyApp1 \
198             --author=gordon \
199             --email="vanamburg@cpan.org" \
200             --verbose
201             Created MyApp1
202             Created MyApp1/lib
203             Created MyApp1/lib/MyApp1.pm # YOUR *CONTROLLER BASE CLASS* !
204             Created MyApp1/t
205             Created MyApp1/t/pod-coverage.t
206             Created MyApp1/t/pod.t
207             Created MyApp1/t/01-load.t
208             Created MyApp1/t/test-app.t
209             Created MyApp1/t/perl-critic.t
210             Created MyApp1/t/boilerplate.t
211             Created MyApp1/t/00-signature.t
212             Created MyApp1/t/www
213             Created MyApp1/t/www/PUT.STATIC.CONTENT.HERE
214             Created MyApp1/templates/MyApp1/C/Home
215             Created MyApp1/templates/MyApp1/C/Home/index.tmpl # DEFAULT HOME PAGE TEMPLATE
216             Created MyApp1/Makefile.PL
217             Created MyApp1/Changes
218             Created MyApp1/README
219             Created MyApp1/MANIFEST.SKIP
220             Created MyApp1/t/perlcriticrc
221             Created MyApp1/lib/MyApp1/C # YOUR CONTROLLERS GO HERE
222             Created MyApp1/lib/MyApp1/C/Home.pm # YOUR *DEFAULT CONTROLLER SUBCLASS*
223             Created MyApp1/lib/MyApp1/Dispatch.pm # YOUR CUSTOM DISPATCHER
224             Created MyApp1/config
225             Created MyApp1/config/config-dev.pl # YOU CONFIG -- MUST BE EDITED BY YOU!
226             Created MyApp1/script
227             Created MyApp1/script/create_dbic_schema.pl # IMPORTANT HELPER SCRIPT
228             Created MyApp1/script/create_controller.pl # ANOTHER IMPORTANT HELPER SCRIPT.
229             Created MyApp1/server.pl # SERVER USES YOUR CUSTOM DISPATCH.PM
230             Created MyApp1/MANIFEST
231             Created starter directories and files
232              
233              
234              
235             =cut
236              
237             =head2 Configure Your Database
238              
239             CGI::Application::Structured is database centric in some sense and expects that you have a database. Before running your
240             app via server.pl you need to configure your database access.
241              
242             The example config is generated at MyApp1/config/config.pl. The contents are shown here.
243              
244             use strict;
245             my %CFG;
246              
247             $CFG{db_dsn} = "dbi:mysql:myapp_dev";
248             $CFG{db_user} = "root";
249             $CFG{db_pw} = "root";
250             $CFG{tt2_dir} = "templates";
251             return \%CFG;
252              
253             Using the root account is shown here as a worst-practice. You should customize the file supplying the correct database dsn, user and passwords for your database.
254              
255             If you do not have a database and want to use an example see "Create Example Database" below before continuing.
256              
257             The configuration file will be found automatically when running with the built in server, but when you deploy your application you may want, or need, to update the config file location in lib/MyApp1/Dispatch.pm to point to your production config file.
258              
259             For information on advanced configuration see: L
260             =cut
261              
262             =head2 Generate A DBIx::Class Schema For Your Database
263              
264             From your project root directory run the helper script to generate DBIx::Class::Schema and Resultset packages. This will use the configuration you supplied in config_dev.pl to produce a DB.pm in your apps lib/MAINMODULE directory
265              
266             ~/dev/My-App1$ perl script/create_dbic_schema.pl
267             Dumping manual schema for DB to directory /home/gordon/dev/MyApp1/lib/MyApp1/DB ...
268             Schema dump completed.
269              
270              
271             Given the example database shown below your resulting DBIx::Class related files and folders would look like this:
272              
273             ~/dev/MyApp1$ find lib/MyApp1/ | grep DB
274             lib/MyApp1/DB
275             lib/MyApp1/DB/Result
276             lib/MyApp1/DB/Result/Orders.pm
277             lib/MyApp1/DB/Result/Customer.pm
278             lib/MyApp1/DB.pm
279              
280              
281             For more information see: L, L
282              
283             =cut
284              
285             =head2 Run Your App
286              
287             Now that your database is configured and the schema generated you can run your app.
288              
289             Run the server:
290              
291             ~/dev/MyApp1$ perl server.pl
292             access your default runmode at /cgi-bin/index.cgi
293             CGI::Application::Server: You can connect to your server at http://localhost:8060/
294              
295             Open your browser and test at
296              
297             http://localhost:8060/cgi-bin/index.cgi
298              
299              
300             For more information on the nature of the development server see: L
301              
302             =cut
303              
304             =head2 Try Plugin::DebugScreen;
305              
306             CAS comes with L. Plugin::DebugScreen provides a very useful stack trace with multi-line source quotations for each level of the stack. cas-starter.pl has put debug.sh in your project root directory. It sets up the environment for Plugin::DebugPage and runs the built in server.
307              
308             Edit lib/MyApp1/C/Home.pm to generate an error to demonstrate the DebugScreen:
309              
310            
311             sub index: StartRunmode {
312             my ($c) = @_;
313              
314             # add this line for demo of debug screen
315             die "testing";
316              
317             $c->tt_params({
318             message => 'Hello world!',
319             title => 'C::Home'
320             });
321             return $c->tt_process();
322            
323             }
324              
325             Run the server in debug mode:
326              
327             ~/dev/MyApp1$ bash debug.sh
328             access your default runmode at /cgi-bin/index.cgi
329             CGI::Application::Server: You can connect to your server at http://localhost:8060/
330              
331             Open your browser and test/demo the Plugin::DebugScreen:
332              
333             http://localhost:8060/cgi-bin/index.cgi
334              
335             Remove the line you added to Home.pm
336              
337             For more information on Plugin::DebugScreen see: L
338              
339             =cut
340              
341             =head2 Create A New Controller
342              
343             This is where the create_controller.pl helper script comes in very handy. create_controller.pl will
344             create a new controller with a default runmode called 'index', and an index template to go with it.
345              
346             As an example we can generate a new module to interact with the Orders table
347             of the example database.
348              
349             ~/dev/MyApp1$ perl script/create_controller.pl --name=Orders
350             will try to create lib/MyApp1/C
351             Created lib/MyApp1/C/Orders.pm
352             will try to create template directory templates/MyApp1/C/Orders
353             Created templates/MyApp1/C/Orders
354             Created templates/MyApp1/C/Orders/index.tmpl
355            
356              
357             You can restart server.pl and view default output at:
358              
359             http://localhost:8060/cgi-bin/orders
360              
361             Add a new runmode to lib/MyApp1/C/Orders.pm to show the orders that we have from the example database.
362              
363              
364              
365             sub list: Runmode{
366             my $c = shift;
367              
368              
369             my @orders = $c->resultset("MyApp1::DB::Result::Orders")->all;
370              
371             $c->tt_params(orders =>\@orders);
372             return $c->tt_process();
373              
374             }
375              
376              
377              
378             Then add a template for this runmode at templates/MyApp1/C/Orders/list.tmpl with the following content:
379              
380              
381            

Order List

382            
383            
Cust NoOrder No
384             [% FOREACH order = orders %]
385            
386             [% order.customer_id %]
387             [% order.id %]
388            
389             [% END %]
390            
391              
392             Restart server.pl and visit page to see list of orders at:
393            
394             http://localhost:8060/cgi-bin/orders/list
395            
396              
397             For advanced information on creating controllers, runmodes and templates see: L, L, L and L.
398              
399             =cut
400              
401             =head2 Creating The Example Database (if you don't already have one)
402              
403             The L distrubution contains an example sql file that you can use for this
404             example app. Use the download link at L on CPAN, grab the archive and extract the file from the 'examples' directory of the distribution.
405              
406             The script will create the 'myapp1_dev' database, create 2 tables and load a few
407             Notice that the create table statements end with 'engine=InnoDB'. This is important since our DBIC generator script will create perl modules to represent database table relationships, based on the metadata in the database. While the InnoDB engine will work, the default engine for mysql will not store the relationship metadata and you would then need to hand-craft the relationships at the botton of the generated DB::Result classes.
408              
409             Example:
410              
411             ~/dev/MyApp1$ mysql -u root -p < example_tables.mysql.ddl
412            
413              
414             The contents of the example sql file are as follows:
415              
416             CREATE DATABASE myapp1_dev;
417             USE myapp1_dev;
418              
419             CREATE TABLE customer(
420             id integer not null auto_increment PRIMARY KEY,
421             last_name varchar(25) null,
422             first_name varchar(25) not null
423             )engine=InnoDB;
424              
425             CREATE TABLE orders(
426             id integer not null auto_increment PRIMARY KEY,
427             customer_id integer not null,
428             order_status varchar(10) default "OPEN" not null,
429             order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP not null,
430             CONSTRAINT orders_customer_id_fk FOREIGN KEY (customer_id) REFERENCES customer(id)
431             )engine=InnoDB;
432              
433             INSERT INTO customer (last_name, first_name) VALUES("Doe","John");
434             INSERT INTO orders (customer_id) VALUES( 1 );
435             INSERT INTO orders (customer_id) VALUES( 1 );
436             INSERT INTO orders (customer_id) VALUES( 1 );
437              
438              
439             If you did not use 'engine=InnoDB' or your database does not support relationships, you can paste the following in the bottom of your "MyApp/DB/Result/Orders.pm" to tell DBIx::Class how the example tables relate:
440              
441              
442             # Created by DBIx::Class::Schema::Loader v0.04006 @ 2009-09-15 16:05:33
443             # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:znOKfDkdRzpL0KHWpfpJ+Q
444              
445             __PACKAGE__->belongs_to(
446             "customer",
447             "MyApp1::DB::Result::Customer",
448             { id => "customer" },
449             );
450              
451             See documentation for L for more information on configuring and using relationships in your model.
452              
453             =cut
454              
455              
456             =head1 Further Reading
457              
458             See L for more information on developer tools package.
459              
460             See L for more information on accessing DBIx::Class from your CGI::Application::Structured modules.
461              
462             See L for form building support that is build into CGI::Application::Structured.
463              
464             See L for more information on using the powerful ORM included with CGI::Application::Structured.
465              
466             See L and L for more information on advanced templating.
467              
468             See L for lots of good ideas and examples that will work with your CGI::Application::Structured app.
469              
470              
471              
472             =head1 BUGS
473              
474             There are no known bugs for this distribution.
475              
476             Please report any bugs or feature requests through the web interface at
477             L.
478              
479             I will be notified, and then you'll automatically be notified of progress on
480             your bug as I make changes.
481              
482              
483             =head1 SUPPORT
484              
485             I recommend joining the cgi-application mailing list.
486              
487             =head1 AUTHOR
488              
489             Gordon Van Amburg
490             CPAN ID: VANAMBURG
491             vanamburg at cpan.org
492              
493             =head1 COPYRIGHT
494              
495             This program is free software; you can redistribute
496             it and/or modify it under the same terms as Perl itself.
497              
498             The full text of the license can be found in the
499             LICENSE file included with this module.
500              
501              
502             =cut
503              
504             #################### main pod documentation end ###################
505              
506             1;
507              
508             # The preceding line will help the module return a true value
509