Tequilla Tutorial
Tequilla Tutorial
* 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
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)
Files
1. Controller
2. model
3. view
4. template
5. language
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
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.
The file
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
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;
DB related code
Echo, print, HTML code
Language related code or entries
The model
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 ?>
If you want you can read more about the model, or just jump to the DAO and VO page
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!
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.
Having a good model results into robust applications and helps avoiding code repetition
So with the hard work of making the model and the controller behind, let's focus on the DAO
and the VO
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.
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
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
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.
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!
Template
We are nearly done now!, But missing parts are normally the hardest in all frameworks. The
view..
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;
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.
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!
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:
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.
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.
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 ?>
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
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
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
$this->template->assign("placeholder", $vo->property);
$this->setlang("mainarray", "optional_specific_entry");
Language file
Location
Naming
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
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 ?>
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.
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
Finally finished! You got a categories page, now let's make recipes a little bit faster before you
fly away