Sie sind auf Seite 1von 18

Tutorial, Your first app

Your first application!


In this tutorial you will learn:

1. How files are organized in Tequila


2. How your code should be organized
3. How to make a complete CRUD (Create Read Update Delete) page
4. How to create a template
5. How to work with multiple languages

* Note: This tutorial DON"T use the fastest way to create the application using Tequila, rather it
tries to help you get familiar with the framework

For this tutorial let's try the famous categories / recipe example

Pre-requisites
We assume you already download and configure a Tequila application, if you haven't you can do
it following this page

Project description
Simple recipes application with recipes categories

Creating database

Run this script from your favorite mySql application


(phpMyAdmin or any other)
DROP TABLE IF EXISTS T_RECIPES;
DROP TABLE IF EXISTS T_CATEGORIES;

CREATE TABLE T_CATEGORIES (


I_IDCATEGORY int NOT NULL AUTO_INCREMENT,
I_NAME varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY(I_IDCATEGORY)
) engine=InnoDB;;

CREATE TABLE T_RECIPES (


I_IDRECIPE int NOT NULL AUTO_INCREMENT,
I_IDCATEGORY int NOT NULL,
I_TITLE varchar(100) NOT NULL DEFAULT '',
I_DESCRIPTION varchar(255) NULL,
I_DATE date NULL,
I_INSTRUCTIONS text NULL,
CONSTRAINT fk_r_c foreign key (I_IDCATEGORY) references
T_CATEGORIES(I_IDCATEGORY),
PRIMARY KEY(I_IDRECIPE)
) engine=InnoDB;

Hey what about the T_'s and I_'s


They are not required, we suggest as a good practice for multiple databases; When you work
with a single database is easy to see your mistakes in field and table naming as the create
instruction will fail when you run it. When you need to migrate your application to a new
database you might discover name, date, status and many other words are reserved in one of
them. So as a simple practice we name all fields I_ and all tables T_.

Your first page


We will need to create 2 pages for this application, categories and recipes, 

Tutorial: Adding categories page


Let's start by checking where files are located in Tequila, then we will add one page at a time, manually so you really get familiar
with it, later on we will show you how to make it automatically (final release only)

Files location

First thing I like knowing when I use any platform or framework is where to find the files and
resources that I need, so here you go:
- Not required (We store the DB script here)
<- Your application and packages
 <- Your application (The PHP part)
 <- Code that handle user interaction
 <- Data Access Objects (one per table)
 <- Your model
 <- All the views, not templates but PHP
pages that manage them
 <- Value objects, think of them as data
structures (one per table)

 <- Reusable code, login, etc.. (Can


download, exchange, make..)
 <- Container for language resources
 <- English language files, add any you need
 <- Container for your templates
 <- Default template

 <- Resources of your template . .

Ok, that was quite exhausting, so what makes a complete page?

Files

A normal page is made of.

1. Controller
2. model
3. view
4. template
5. language

For each database table:

1. DAO
2. VO

Very important: To allow drag and drop of classes the name of the file and the name of the
class must be the same

Do i have to follow this structure?


You can actually drag and drop the classes anywhere you want, but keeping this structure will help you work and exchange code.
When you detect more than one application uses the same classes you can create a package and move the code to the packages
folder, then you can decide if you keep the files split in model, view, controller or just put them all in the package root.

Categories functionality

For this example we are making full CRUD pages, Create, Read, Update and Delete, we will of
course add Browse and other usefull methods

The controller

Controller

The controller is the piece of code that respond to the user actions, then modifies the model play
around with it and finally call the view to render the screen.

In Tequila the name of your controller is normally passed as a task: task=yourcontroller and the


method as an action &action=Browse

 To respond to a new method simply add a function in the class

The file

So let's create categories controller, to start we add a file called categories.php and we place it


on:

app/includes/controllers/categories.php

The code
Now the code, this class should include: browse, view, delete, edit, update, addnew and insert
methods (at least), that sounds like a lot of work..

Controller code:

1 <?php
2 class categories extends application_controller_crud {
3 protected $mode = 'browse';
4 protected $modeltype = 'categories_model';
5 protected $viewtype = 'categories_view';
6 protected $idfield = 'I_IDCATEGORY';
7 protected $no_id_modes = array("Browse", "addNew",
"saveAjax","Insert");
8 }
9 ?>

That's it! Now your controller is ready to respond to all common actions, List records, view, edit,
delete, add new and even ajax saving (soon we are adding all methods with XML and JSON
replies)

Now you can read more about the controller or jump to the model

What's that code?

 mode: Defines the default mode if no other specified (i.e. for invoice it might be
addNew)
 model and view type: You can define here the class name, no naming is forced so you
can reuse a complex model in many pages
 idfield: For CRUD pages we normally use the id of the object, other pages can live
without this (non autonumeric fields and multiple fields keys are supported, but we
don't review in this tutorial)
 no_id_modes, controller calls are pre-validated to stop execution if no ID is provided
(i.e. Read, Update) here we specify which modes should run without validation. If your
class contain mostly no_id_modes, you can replace for the opposite $id_modes;

What goes in the controller?

 Includes all the code that reads post/get/request/session/cookies etc.


 User events are normally "mapped" to one function in the class
 Call methods from the model
 Call methods from the view

What doesn't goes in the controller?

 DB related code
 Echo, print, HTML code
 Language related code or entries

The model

Now let's code the core part.


What our model will do:

Our model will do all CRUD model actions, insert, update, delete, get and object, return a collection of
objects, etc.

The model receives the information from the controller, information can come as single parameters or
as complete objects. 

The code

1 <?php
2 class categories_model extends crud_model {
3 protected $daotype = 'categories_DAO';
4 }
5 ?>

And.. that's it... 

If you want you can read more about the model, or just jump to the DAO and VO page

Does the model need to inherit / extend crud_model?


No, if your application is simple and the model represents a single table, follow this approach.

If your application is complex, Create your classes, use the DAO's and VO's to pass and store information
and then create a class to interact with your model. Give the name of that one to your controller!

I need extra functionality, where can I add?


Need a non provided function: just add as public
Need to modify an existing: overload (also just add copying the signature from the parent)

Can I use my existing model?

Absolutely, you can also take any open source code and drop it anywhere. 

Just remember the only rule for your classes to be found is : class name == filename.

What's in the model

The model is a class or set of classes where:

 All business rules are located


 All DB processing is made
 All info manipulation, transformation is done

Having a good model results into robust applications and helps avoiding code repetition

What's NOT in the model

 Contain any reference to user submitted information


 Contain global variables that make application difficult to maintain 
 Presentation layer instructions, echo
 Contain any HTML code
 Contain any messages, language entries

DAO & DTO's

So with the hard work of making the model and the controller behind, let's focus on the DAO
and the VO 

Notice: DTO were formerly called VO

Naming standards and casing 


As a useful convention, DAO and VO should have the same name with a different prefix, in this
case categories (you can also call them after the table t_categories)
Case is critical for database switching, we recommend using capital letters always to refer to
tables and fields remember PHP is case sensitive!

DAO
Data Access objects, allow us to keep the database code out of the model and to avoid repeating
statements. They also help when switching database types.

The DAO will contain the methods and information to map the objects to the DB.

Let's create the file:

includes/app/dao/categories_DAO.php

DAO Code

1 <?php
2 class categories_DAO extends DAO {
3 protected $table = "T_CATEGORIES";
4 protected $keyField = "I_IDCATEGORY";
5 protected $classType = "categories_VO";
6 }
7 ?>

More on DAO

There's more on DAO's that meet the eye, we will add soon more information on the other
DAO's

 DAO_unique: For not auto numeric keys


 DAO_blob: For VO's that contain pictures or very long text
 DAO_service: For VO's that doesn't map to DB

VO
Value Objects are design pattern used to transfer data between software applications or layers.

Normally they represent a single row in the database but they can contain any data structure

Let's create the file:


includes/app/VO/categories_VO.php

VO Code

1 <?php
2 class categories_VO{
3 public $I_IDCATEGORY, $I_NAME;
4 }
5 ?>

And that's it.. just add one variable for each field in your table.

How to use the VO's?


When you use the DAO to get information from the database you will normally get a VO object,
you can access it's properties like any object:
$myobject->myproperty;

Does VO's make sense? why not using parameters?

Perhaps you cannot see the advantage of creating and passing an object with just an id and a
name but it sure make sense as the object properties multiply, while arrays could do the job VO's
give us greater control and more possibilities.

Done! Take me to template!

More on DB? go to access data page, or read more about  DAO 

Template

We are nearly done now!, But missing parts are normally the hardest in all frameworks. The
view..

What makes the view in Tequila?


 A basic HTML template
 A PHP file that uses the template
 A language file 

First let's see the code


In Tequila we only use one template per page, there are already enough files around to create one
more for each method! 
Add a file:

templates/basic/categories.html

The template code is very easy but quite long, we suggest you to see it on Dreamweaver or
another HTML application.
<!-- INCLUDE BLOCK : header -->
<!-- START BLOCK : title -->
<h3>{title}</h3>
<!-- END BLOCK : title -->
<!-- START BLOCK : Msg -->
<p class="Warn">{message}</p>
<!-- END BLOCK : Msg -->
<!-- START BLOCK : Error -->
<p class="Error_page">{message}</p>
<!-- END BLOCK : Error -->
<!-- START BLOCK : Exit -->
<p>
<input name="exit" type="button" id="exit"
onclick="MM_goToURL('parent','{exitUrl}');return document.MM_returnValue"
value="{exit}" />
</p>
<!-- END BLOCK : Exit -->
<!-- START BLOCK : Edit -->
<script language="javascript" type="text/javascript">
// Vars should be declared in JavaScript include
function validateOnSubmit(f) {
var elem;
var errs=0;
// execute all element validations in reverse order, so focus gets
// set to the first one in error.
if (!validateLength(f.I_NAME, 'err_I_NAME' ,4,50 , true)) errs += 1;

if (errs>1) alert('There are fields which need correction before


sending');
if (errs==1) alert('There is a field which needs correction before
sending');
return (errs==0);
};
</script>
<form name="editForm" method="post" action="" onsubmit="return
validateOnSubmit(this);">
<table width="90%" border="0" cellpadding="0" cellspacing="2"
class="nice">
<tr>
<td class="inverse">{lbl_I_NAME}</td>
<td ><input name="I_NAME" type="text" class="input_Medium"
id="I_NAME" value="{I_NAME}" onchange="validateLength(this, 'err_I_NAME' ,3,40
, true);" />
<span class="Error" id="err_I_NAME">&nbsp;{err_I_NAME}</span>
</td>
</tr>
<tr>
<td valign="top">&nbsp;</td>
<td ><span id="msgajax">&nbsp;</span></td>
</tr>
<tr>
<td><input name="mode" type="hidden" id="mode;" value="{mode}" />
<input name="I_IDCATEGORY" type="hidden" id="I_IDCATEGORY"
value="{I_IDCATEGORY}" />
</td>
<td ><input name="btnAjax" type="button" id="btnAjax"
value="{saveajax}" onclick="saveformajax(this.form,
'{saveajaxUrl}','I_IDCATEGORY');" />
<input name="Submit" type="submit" value="{submit}" />
<input name="Cancel" type="button" id="Cancel"
onclick="MM_goToURL('parent','{exitUrl}');return document.MM_returnValue"
value="{exit}" />
</td>
</tr>
</table>
</form>
<!-- END BLOCK : Edit -->
<!-- START BLOCK : View -->
<table width="90%" height="61" border="0" cellpadding="0" cellspacing="2"
class="nice">
<tr>
<td height="28" class="inverse">{lbl_I_NAME}</td>
<td > {I_NAME} </td>
</tr>
<tr>
<td height="27"></td>
<td ><input name="goEdit" type="button" id="goEdit"
onclick="MM_goToURL('parent','index.php?
task=categories&mode=Edit&I_IDCATEGORY={I_IDCATEGORY}');return
document.MM_returnValue" value="{edit}" />
<input name="goDelete" type="button" id="goDelete"
onclick="ConfirmAndgoToURL('index.php?
task=categories&mode=Delete&I_IDCATEGORY={I_IDCATEGORY}','{delete_confirm}
{labelDelete}?')" value="{delete}" />
<input name="Cancel" type="button" id="Cancel"
onclick="MM_goToURL('parent','index.php?task=categories&mode=Browse');return
document.MM_returnValue" value="{exit}" /></td>
</tr>
</table>
<!-- END BLOCK : View -->
<!-- START BLOCK : List -->
<table border="0" cellpadding="2" cellspacing="1" class="sortable2">
<thead>
<tr>
<th >{lbl_I_NAME}</th>
<th class="skipsort">{lbl_view}</th>
</tr>
</thead>
<tbody class="scrollable">
<!-- START BLOCK : row -->
<tr class="{cssstyle}">
<td>{I_NAME}</td>
<td><a href="{viewLink}">{view}</a></td>
</tr>
<!-- END BLOCK : row -->
</tbody>
<tfoot>
<th> <input name="addNew" type="button" id="addNew"
onclick="MM_goToURL('parent','{addNewUrl}');return document.MM_returnValue"
value="{addNew}" />
</th>
<th class="pages">
<!-- START BLOCK : pagination -->
<ul class="pagination">
<!-- START BLOCK : linkpage -->
<li {class}><a href="{url}">{label}</a></li>
<!-- END BLOCK : linkpage -->
</ul>
<!-- END BLOCK : pagination --></th>
</table>
<!-- END BLOCK : List -->
<!-- START BLOCK : ajax -->
<?xml version="1.0" encoding="iso-8859-1"?>
<r>
<status>{status}</status>
<idx>{idx}</idx>
<msg>{msg}</msg>
</r>
<!-- END BLOCK : ajax -->
<!-- INCLUDE BLOCK : footer -->

Ok, don't get scared if you know HTML you will see there's nothing in here, all is pure HTML
code, with some CSS, some javascript for validation and table sorting and a pagination block so
you get the whole idea.

 Header: PHP block that is common to all pages


 Block Title, a heading to show where we are to the user
 Block Message and Error, messages, you can customize to show icons or anything else
 Block Exit, add a button to navigate out of the page
 Block Edit, 
o Javascript to validate name is entered
o A table with text controls
o Some hidden fields
o buttons
 Block View;
o A table with the fields for display
 Block List,
o A table that uses some cool css / javascript to make it sortable
o Block ROW, the block the code that has to repeat for each category
o Add new button
o Pagination block (In case you have lots)
 A block for ajax (not required)
 The footer, same as header common PHP /HTML code
Studying the code

You can see all code is pure HTML the blocks are HTML comments, there is some not required
javascript, some pagination blocks etc. We believe any designer can use/create a similar template
with some guidelines, then you Javascript developer or yourself can add the JS blocks.
As you see there is no language entries, titles, or text in the file and not a single control structure,
IF, ELSE, FOR, WHILE, LOOP,etc..
You can go now to the view page or read more about templates in Tequila!

The template technology

We have use many templates and unfortunately I belong to the small group of people that believe
most template engines got it all wrong :(
Templates are made for:

 Separate code from presentation


 Make easy to update / modify the look of a system
 Have different views for different clients

Why template engines got it wrong?

Originally the idea was to keep designers making nice pages and developers doing the coding, so
template engines were born, unfortunately they got so complex that they become another
language in the equation. A language that I believe no one needs.. 
The HTML is still not clean and well you cannot code it in PHP now you need to learn your
template language; Conditionals, object access, loops.. Is this the job of a designer? or a
developer? I think none, so well we didn't separate presentation from code, we just use a new
one.

So what Tequila likes

After using many  I decide to implement a template that I liked for long time, unfortunately is
not free for commercial projects but well is not expensive. In the future when we get some time
we will replace this template engine for one that allows commercial projects (want to
participate? we know is not hard, we just have no time, contact me pls if you want to get
involved! all info on sourceforge, or add a comment)
We use a slightly modified version of templatepower you can check the help in the site to get all
the grammar.
This template use PURE html code + HTML comments to mark blocks and normal
{placeholders}, there is no variables, object access or anything else. 

What do I need to know for my template?


Not really much you pretty much just need to know,
<!-- START BLOCK : yourblock -->
{a_placeholder}
<!-- START BLOCK : mynestedblock-->
{another_placeholder}
<!-- START BLOCK : mynestedblock-->
<!-- END BLOCK : yourblock -->

The View

In Tequila the view is made with PHP code, a consequence of keeping the template clean is that the
code that links the model to the template has to be added somewhere.. For us this is the view.

Location,
Add the file:

includes/app/views/ categories_view.php

The code

1 <?php
2 class categories_view extends application_view_crud {
3 protected $idfield = 'I_IDCATEGORY';
4 protected $controller_type = 'categories';
5 public function show_view(&$vo)
6 {
7 $this->addtitle();
8 $v = new view_object($this->template,$vo,
array('parent'=>'View'));
9 $v->addlang('label');
10 $v->addlang('msg', 'delete_confirm');
11 $v->addlang('btn');
12 $v->getview();
13 }
14 public function show_edit(&$vo, $isnew = false)
15 {
16 $this->addtitle();
17 $this->addJS('ajax.js');
18 $v = new view_editor($this->template, $vo,
array('parent'=>'Edit'));
19 $v->addlang('label');
20 $next_mode = ($isnew ? 'Insert':'Update');
21 $v->addLabel('mode', $next_mode);
22 $exitUrl = "?
task=categories&I_IDCATEGORY={I_IDCATEGORY}&mode=" . ($isnew ? 'Browse' :
'View');
23 $v->addbtn('submit', '');
24 $v->addbtn('exit', $exitUrl);
25 $v->addbtn('saveajax','?
task=categories&mode=saveAjax&rrt=xmlt');
26 $v->getview();
27 }
28 }
29 ?>

What's that code?


Let's see..

 First you can notice there's only 2 modes, again we use inheritance to solve common methods
 You will notice there's no template assignments (check after)
 You can also notice we use $v (see view strategies later on this document)
 We assign lang resources (see next step, language files)

View strategies

When we start coding we noticed most of the code of the view was creating blocks and assigning values,
so we decided to create a set of strategies to render most common views, you will find this view under 

Tequila_fwk/includes/views

This views solve most common problems saving you work without taking out versatility (you are not
forced to use naming or anything else) see view strategies section for more info

Current view include

 Alternate table
 array
 editor
 loop
 loop with grouping
 object
 organizational chart
 page tables
 pagination
 YUI dynamic tree
 YUI fixed tree
 XML data
 XML complex data
 XML status

I have some very complex screens I would like to reuse

You can call the same view from different controllers or you can create a strategy and reuse among
many applications, making a strategy is not hard, it actually takes moving your code to one function,
extending view_strategy and changing the hardcoded sections. see view_strategies section for more info

I need a template assignment and to create my block manually, what can i do?

You can use normal template methods, the template is available as an object of the class under:
$this->template

For creating a block:

$this->template->newBlock("blockname");    or    $this->addblock("blockname");

For assigning a value:

$this->template->assign("placeholder", $vo->property);

Language file assignment


Language files resources can be assigned individually or collectively, the structure of a language file is in
arrays (see next section the language file) so you can call

$this->setlang("mainarray", "optional_specific_entry");

Language file

You are making a great application why limit it to one language!

Location

You will find language resources under


languages/XX

Naming

Language file must follow the name of the controller

Adding languages

You can copy EN folder to create your own ES/ DE / NO / FI /JP /TH or any other.

UTF8 notice

All utf8 languages are supported, but beware BOM is evil and can make Ajax calls fail, apparently it send
some header info before when the file is included so just save your files without BOM

Let's make our language file,

Please create

language/EN/categories.php

The code

1 <?php
2 global $lang;
3 #-------------------- TITLE FIELDS -----------------------------
4 $lang["title"] = "Categories Maintenance";
5
6 #----------- TAGS FOR INPUT FIELDS -----------------------------
7 $lang["label"]["lbl_I_NAME"] = "Category name";
8
9 #----------- HEADER FOR LIST COLUMNS ---------------------------
10 $lang["list_header"]["im_recipes"] = "See recipes!";
11 ?>

How Tequila organize the language file?

Again we were feeling lazy assigning every define for language files, so we decide the way to
use "pseudo-inheritance" was to use an array, there is a global language file that defines most
buttons, error messages, navigation labels, etc. 

Language entries are grouped in arrays, so for example:

All buttons are part of $lang['btn'] array, 


All messages are part of $lang["msg"] array

While for buttons it make no sense to apply all together, all labels can be assigned in one go
saving a lot of effort. it also contributes to the application looking more standard and we avoid
loading gigantic language files (1 file per application) while reusing the labels 

The global language file is : general_lang.php

Finally finished! You got a categories page, now let's make recipes a little bit faster before you
fly away

Das könnte Ihnen auch gefallen