Building A Zinc App
From Deep Thought
Contents |
How to build a Zinc Application.
These instructions assume your are on a linux server with standard access to CPAN and a recent version of Perl installed.
Prepare The Application Workspace
Get Zinc.
cpan -i Zinc::Director cpan -i Zinc::Act cpan -i Zinc::Memory cpan -i Zinc::View
Create your custom extension placeholders.
The custom extensions are where you'll put in any custom functionality that is not part of the base Zinc modules. Normally you'll want to have some custom view and action items.
mkdir zincmods cd zincmods vi MyView.pm vi MyAct.pm vi MyMemory.pm
MyAct.pm
package MyAct;
use strict;
use base('Zinc::Act');
MyMemory.pm
package MyMemory;
use strict;
use base('Zinc::Memory');
MyView.pm
package MyView;
use strict;
use base('Zinc::View');
Create your templates directory.
This is where your HTML templates, CSS, and other static pages for the application view module will live. The default template for a Zinc application is called "plainjane".
mkdir templates mkdir templates/plainjane vi templates/plainjane/wireframe.html
wireframe.html
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>Crowd Keeper</title>
<link rev="made" href="mailto:info%40cybersprocket.com" />
<link rel="stylesheet" type="text/css" href="<%SELF(TemplateDir)%>site.css" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
My first Zinc Application.
</body>
</html>
Build the launcher
The launcher is your index.pl file that defines whether you'll use the default Act, Memory, and View classes of Zinc or your extended (custom) versions of each. It also kicks off any action processing as well as rendering your pages. A simple launcher is listed below:
#!/usr/bin/perl -w
use lib './';
use Zinc::Director;
use lib './zincmods/';
use MyView;
use MyAct;
my $Director = new Zinc::Director(
CodeStart => '<<',
CodeEnd => '>>',
DBName => 'my_postgres_db',
DBUser => 'my_username',
ViewModule => 'MyView',
ActModule => 'MyAct'
);
print $Director->{WebIO}->header;
$Director->Act;
$Director->Display('wireframe');
exit;
Create Your Data Structures
Rather than just jump right into PostgreSQL and start building your data structures, we prefer to take a more structured approach. Our approach stores the data definitions in a text file containing SQL commands. This allows us to easily modify our data structure and start over from scratch when we are done with our develompent.
Our naming convention is to create a file named current_schema.sql that always contains the data structure and initial data seeding elements for the CURRENT VERSION of the application. As the application ages we relegate the current_schema.sql to a relevant name such as v0.1.1_schema.sql to allow people to follow along with the ugprades.
Sometimes we include the "stepping stone" files that migrate people between versions. These files are often names things like "upgrade_v01.1_v0.1.2.sql" and contains all the SQL necessary to move an existing v0.1.1 installation to the v0.1.2 release.
Create The Data Structure Builder
mkdir ./data vi ./current_schema.sql
current_schema.sql
--- Project: Crowd Keeper
--- Author: Cyber Sprocket Labs (www.cybersprocket.com), Lance Cleveland
--- Version: 0.1
--- (c) 2008 - All right reserved, worldwide.
--
--- Clean install schema
---
--- =======================================================================
--- Primary Tables
--- =======================================================================
---
--- TABLE: GROUPS
---
create table groups(
grp_id serial NOT NULL PRIMARY KEY,
grp_name char(50) NOT NULL UNIQUE CHECK (grp_name <> '')
);
---
--- TABLE: USERS
---
create table users(
user_id serial NOT NULL PRIMARY KEY,
user_name char(50) NOT NULL UNIQUE CHECK (user_name <> ''),
user_pwd char(50) NOT NULL CHECK (user_pwd <> '')
);
--- =======================================================================
--- Mapping Tables
--- =======================================================================
---
--- TABLE: GROUPUSERS
--- Attach users to 1..n groups
---
create table groupusers(
gu_id serial NOT NULL PRIMARY KEY,
gu_grp_id int NOT NULL
REFERENCES groups(grp_id) ON DELETE CASCADE,
gu_user_id int NOT NULL
REFERENCES users(user_id) ON DELETE CASCADE
);
--- =======================================================================
--- Views
--- =======================================================================
create view groupdetails as
select * from groupusers
left join groups on groupusers.gu_grp_id = groups.grp_id
left join users on groupusers.gu_user_id = users.user_id
;
Create The Database
If your database creation commands in the SQL file are "clean" the final command will create your tables, views, etc. for your application. These commands assume you have already setup your PostgreSQL users.
# psql -U<username> template1 template1=> create database <your_db_name>; template1=> \c <your_db_name> template1=> \i ./schema-current.sql
Tips & Tricks
Database Interaction
Name your data connections
Synopsis
Naming statement handles when doing various selects and/or updates is important.
The underlying Postgres::Handler does some special caching stuff that causes primary keys to stomp all over each other if you’re not careful.
The best way to avoid issues is to simply name all of your statement handles. It actually allows Zinc to run more efficiently.
Details
- Look at the examples below for a sample code segment and corresponding template.
- If the ListPeople function does not used a named data handle it stomps all over ListThings and vice-versa causing odd results.
- If you don't do this then subsequent view commands might fail.
Example
Code
sub ListPeople {
my $cmd = "SELECT * FROM people WHERE person= ".$pid;
$self->Memory->PrepLEX( -cmd=>$cmd, -name=>'person');
}
sub ListThings {
my $cmd = "SELECT * FROM things WHERE thing=".$tid;
$self->Memory->PrepLEX( -cmd=>$cmd, -name=>'thing');
}
Template
<h1>This is my template page.</h1> Show a list of people:<br> Z_ListPeople_Z Show a list of things:<br> Z_ListThings_Z
