A smart starter template for Catalyst.
catalyst.pl default generator creates a basic app template. You get a psgi file, Makefile.PL and basic directory structure.
However, real world apps usually needs a bit more: Database, User management, and a JavaScript/CSS framework (or two).
ctstarter.pl aims to provide a true base template for a catalyst web application.
catalyzer takes a template and some configuration options, and generates the starter application for you according to the template.
Each template is a collection of Features, with possible default values for the features.
We also included a default template that generates a catalyst application with SQLite database, basic user management, an HTML view and some TT templates using Twitter Bootstrap.
Create an app with a builtin default template:
catalyzer.pl --appname My::App --template templates/default
catalyzer.pl --appname My::App --template https://github.com/ynonp/catalyzer-spa-template.git
A template can be customized using a configuration file. The meaning of the keys in the configuration depends on the template. For example, the default template takes only a single configuration option: dsn.
You can pass a configuration file using --config-file. Here's a sample config.json you can use:
{
"appname" : "My::Simple::App",
}
And the full catalyzer command:
catalyzer.pl --appname My::App --template templates/default --config-file config.json
Adds a lib/db directory, and inside it initial DBIx::Class Schema and Result-sets for managing users and roles.
db
├── Schema
│ └── Result
│ ├── Role.pm
│ ├── User.pm
│ └── UserRole.pm
└── Schema.pm
DBIx::Class::Migration is a great tool to manage upgrading to the Schema definitions and the DB.
ctstarter.pl gives you a first migration under share directory, along with a simple ready to use SQLite DB.
A new script is created in script directory called myapp_upgrade_db.pl
. After adding Result Sets, use this script to upgrade your database.
share/
├── db-schema.db
├── fixtures
│ └── 1
│ └── conf
│ └── all_tables.json
└── migrations
├── SQLite
│ └── deploy
│ └── 1
│ ├── 001-auto-__VERSION.sql
│ └── 001-auto.sql
└── _source
└── deploy
└── 1
├── 001-auto-__VERSION.yml
└── 001-auto.yml
ctstarter.pl uses Bootstrap view helper to create an HTML view, along with a starter set of .tt2 templates.
Twitter bootstrap is assumed to be hosted on the cloud, but you can edit any of the templates generated in root/src
or root/lib
.
Here's what you'll get:
root/
├── lib
│ ├── config
│ │ ├── main
│ │ └── url
│ └── site
│ ├── footer
│ ├── header
│ ├── html
│ ├── layout
│ ├── sidemenu
│ └── wrapper
├── src
│ ├── error.tt2
│ ├── login
│ │ └── login.tt2
│ ├── message.tt2
│ ├── ttsite.css
│ └── welcome.tt2
Rafael Kitover wrote a great article on how to implement user management in a Catalyst app. ctstarter.pl implements his suggestions into your app.
Only Blowfish hash is stored in the DB, and authentication is performed automatically using CatalystX::SimpleLogin
ctstarter.pl creates:
- Result sets for users and roles
- Initial admin user (username: admin, password: ninja)
- A new controller
lib/MyApp/Controllers/Members.pm
with a base chain for member protected area (/members) - A new script
reset_admin_password.pl
which lets you choose a new admin password. login/login.tt2
template acting as a login form- A simple demo route
/members/hello
that requires login.
To see how everything works, just point your browser to /members/hello
.
A template is basically a list of features, with data files for each feature. Here's what the default template looks like:
templates/default/
├── features
│ ├── DBIx
│ │ ├── DB.pm
│ │ ├── Schema.pm
│ │ ├── db-schema.db
│ │ └── upgrade_db.pl
│ ├── TwitterBootstrapView
│ │ ├── HTML.pm
│ │ ├── css
│ │ │ ├── bootstrap-theme.css
│ │ │ ├── bootstrap-theme.min.css
│ │ │ ├── bootstrap.css
│ │ │ └── bootstrap.min.css
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ └── glyphicons-halflings-regular.woff
│ │ ├── include
│ │ │ ├── layout
│ │ │ │ └── simple
│ │ │ └── login
│ │ │ └── login.tt
│ │ └── js
│ │ ├── bootstrap.js
│ │ └── bootstrap.min.js
│ └── UserManagement
│ ├── Members.pm
│ ├── Role.pm
│ ├── User.pm
│ ├── UserRole.pm
│ └── reset_admin_password.pl
└── features.yaml
10 directories, 23 files
Each template needs an index file named features.yaml. Here's the one from our default template
- DefaultGenerator
- TwitterBootstrapView
- AddPlugins:
- StackTrace
- DBIx:
dsn: dbi:SQLite:dbname=share/db-schema.db
- UserManagement
As you can see, it lists all the features that will be used in the
template. All features are searched in namespace
CatalystX::ProjectBuilder::Features
, so for example DefaultGenerator
feature is just a class named
CatalystX::ProjectBuilder::Features::DefaultGenerator
.
Each feature takes input arguments from two sources: Default arguments
given in features.yaml, and runtime arguments given as a configuration
file to catalyzer.
In the above features.yaml, the DBIx feature expects to get dsn
, and
uses a default value dbi:SQLite:dbname=share/db-schema.db
.
Features also deploy files which are part of the template.
To create a new template do the following:
- Start with the existing default template
- Change the features you need
- Modify default parameters for these features
- Modify deployment files for these features
- Write new features as needed
Catalyzer will automatically load all .pm files under your template's
features/
folder, as well as any feature specified in the
features.yaml file by namespace.
A feature is just a class that provides 3 functions:
- process
- post_process
- required_keys
You'll also get a lot of functionality by including the 'Feature' role.
The process function is called BEFORE the resulted Catalyst app is loaded. You can use it to create files or modify config files, add plugins etc.
After all feature's process
functions were called, catalyzer loads the
resulted Catalyst app and starts calling post_process on each feature.
post_process accepts, in addition to $self, the catalyst app as its
first argument.
This method returns a list of configuration keys the feature needs to run. Catalyzer checks all required keys were passed in before running the feature.
Let's take TwitterBootstrapView feature as an example and see how it is implemented.
package CatalystX::ProjectBuilder::Features::TwitterBootstrapView;
use Moose;
with 'CatalystX::ProjectBuilder::Feature';
with 'CatalystX::ProjectBuilder::GenFiles';
sub required_keys {}
sub process {
my ( $self ) = @_;
$self->gen_dir({ from => ['css'], to => ['root', 'static', 'css'] });
$self->gen_dir({ from => ['js'], to => ['root', 'static', 'js'] });
$self->gen_dir({ from => ['fonts'], to => ['root', 'static', 'fonts'] });
$self->gen_dir({ from => ['include'], to => ['root']});
my @app_path = split /::/, $self->conf->{appname};
$self->t_gen_file('HTML.pm', { to => ['lib', @app_path, 'View', 'HTML.pm']});
}
The class consumes two roles: Feature
and GenFiles
. Feature
provides
empty process() and post_process(), as well as support for input
configurations through $self->conf.
GenFiles
provides the ability to deploy files from the template dir to
the application dir using gen_file, gen_dir or t_gen_file.
-
gen_file simply copies the file using File::Copy::Recursive
-
gen_dir copies a directory using File::Copy::Recursive
-
t_gen_file uses Template to render the file, providing $self->config as the stash