Three-Tier Development with PHP 5
Pages: 1, 2
Smarty files
It's time to create several files for Smarty:
include.php
1 <?
2 require('Smarty.class.php');
3 $smarty = new Smarty;
4 $smarty->template_dir = 'templates/';
5 $smarty->compile_dir = 'templates_c/';
6 $smarty->config_dir = 'configs/';
7 $smarty->cache_dir = 'cache/';
?>
This script instantiates a new Smarty object for the application.
index.php
1 <?
2 require("include.php");
3 $smarty->assign('TITLE','ACCESS MySQL DATABASE IN THREE TIERS WITH PHP');
4 $smarty->assign('HEADER','WHAT WISH DO ?');
5 $smarty->display('index.tpl');
?>
This script shows how to assign values to variables with Smarty. It calls include.php on line 2.
insert.php
1 <?
2 require("include.php");
3 $smarty->assign('TITLE','INSERT DATA');
4 $smarty->assign('HEADER','Insert Data');
5 $smarty->assign('data1','First Name');
6 $smarty->assign('data2','Last Name');
7 $smarty->assign('data3','email');
8 $smarty->display('insert.tpl');
?>
Much like the previous script, this adds variables that will appear in the insert.tpl template.
save.php
1 <?
2 require_once('DB/DataObject.php');
3 require('configDB.php');
4 $user = DB_DataObject::factory('user');
5 $user->first_Name = $x;
6 $user->last_Name = $y;
7 $user->email = $z;
8 $user_Id = $user->insert();
9 $user->update();
10 echo "<script>location.href='index.php'</script>";
11 ?>
This script saves data by using a PEAR::DataObject for the user
table. Line 2 loads the class DataObject, and line 3 calls configdb.php
to connect to the database. Line 4 creates an instance of a user
object (see User.php).
Lines 5 through 7 pass the variables collected from the form in
insert.tpl ($x, $y, and $z) in
order to save the data in the database. The primary key of the table is an
autoincrement column, so it doesn't need a value there. Line 8 inserts the
object, and line 9 carries out an update.
view.php
1 <?
2 require_once('DB/DataObject.php');
3 require('configDB.php');
4 require("include.php");
5 $user = DB_DataObject::factory('user');
6 $user->find();
7 while ($user->fetch()) {
8 $smarty->append('users', array(
'ID' => $user->user_Id,
'FIRSTNAME' => $user->first_Name,
'LASTNAME' => $user->last_Name,
'EMAIL' => $user->email,
));
}
9 $smarty->assign('TITLE','List Users');
10 $smarty->assign('HEADER','List User');
11 $smarty->assign('data0','User_Id');
12 $smarty->assign('data1','First Name');
13 $smarty->assign('data2','Last Name');
14 $smarty->assign('data3','email');
15 $smarty->display('view.tpl');
16 ?>
This script displays all of the data stored in the user table.
It loads PEAR::DataObject and include.php (to assign variables of
Smarty) that to be shown in the template view.tpl. Line 5 creates a factory of
user objects. Line 6 issues a find, which is
equivalent to SELECT * FROM user. After selecting the data, it's
time to store it for the template via fetch(). This returns one
record at a time, which the code stores in a template variable named
users, append()ing each row, named by the keys
ID, FIRSTNAME, LASTNAME, and
EMAIL.
Lines 9 through 14 assign values to other Smarty variables.
All of these .php files should go in the dataobjects directory.
Now for the templates, there are index.tpl, list.tpl, and save.tpl. Here is their code:
index.tpl
1 <html>
2 <head>
3 <title>{$TITLE}</title>
4 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5 </head>
6 <table align="center">
7 <tr>
8 <td>
9 <b>{$HEADER}</b>
10 </td>
11 </tr>
12 </table>
13 <table width="250" border="1" align="center" >
14 <tr>
16 <td align="center">
17 <input type="button" name="insert" value="Insert"
onclick="javascript:location.href='insert.php';">
18 </td>
19 </tr>
20 <tr>
21 <td align="center">
22 <input type="button" name="view" value="View"
onclick="javascript:location.href='view.php';">
23 </td>
24 </tr>
25 </table>
26 </body>
27 </html>
This template is the main page of the system. It shows two variables,
$TITLE and $HEADER, in lines 3 and 9,
respectively. These values of the variables come from index.php.
Later comes a table with two buttons, Insert and View, which have those respective actions. If the user clicks on Insert, the server invokes insert.php (see line 17). If the user clicks on View, this calls view.php (see lines 3 and 4 of that script).
insert.tpl
1 <html>
2 <head>
3 <title>{$TITLE}</title>
4 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5 </head>
6 <body>
7 <form name="form1" action="save.php" method="post">
8 <table width="300" border="1" align="center" >
9 <tr>
10 <td align="center">
11 <b>{$HEADER}</b>
12 </td>
13 </tr>
14 <tr>
15 <td>
16 {$data1}
17 <input type="text" name="x">
18 </td>
19 </tr>
20 <tr>
21 <td>
22 {$data2}
23 <input type="text" name="y">
24 </td>
25 </tr>
26 <tr>
27 <td>
28 {$data3}
29 <input type="text" name="z">
30 </td>
31 </tr>
32 <tr>
33 <td align="center">
34 <input type="submit" name="Submit" value="Add">
35 <input type="button" name="Reset" value="Return/Cancel"
onclick="javascript:location.href='index.php';">
36 </td>
37 </tr>
38 </table>
39 </form>
40 </body>
41 </html>
This template has a form and two buttons, Add and Return/Cancel.
The user enters data for the first name, last name, and email fields (lines 16, 22, and
28). insert.php expects to receive this information in variables named
x, y, and z (lines 17, 23, and 29).
Clicking on the Add button calls save.php (see line 7) to perform the
save. In the contrary case, if the user clicks on Return/Cancel, it executes
index.php (line 35).
view.tpl
1 <html>
2 <head>
3 <title>{$TITLE}</title>
4 </head>
5 <body>
6 <table align="center">
7 <tr>
8 <td align="center">
9 <b>{$HEADER}</b>
10 </td>
11 </tr>
12 </table>
13 <table width="500" border="1" align="center">
14 <tr>
16 <td align="center">
17 <b>{$data0}</b>
18 </td>
19 <td align="center">
20 <b>{$data1}</b>
21 </td>
22 <td align="center">
23 <b>{$data2}</b>
24 </td>
25 <td align="center">
26 <b>{$data3}</b>
27 </td>
28 </tr>
29 {section name=display loop=$users}
30 <tr>
31 <td>
32 {$users[display].ID}
33 </td>
34 <td>
35 {$users[display].FIRSTNAME}
36 </td>
37 <td>
38 {$users[display].LASTNAME}
39 </td>
40 <td>
41 {$users[display].EMAIL}
42 </td>
43 </tr>
44 {/section}
45 <br>
46 </table>
47 <br>
48 <table align="center">
49 <tr>
50 <td align="center">
51 <input name="vol" type="button" value="Return"
onclick="javascript:location.href='index.php';">
52 </td>
53 </tr>
54 </table>
55 </body>
56 </html>
This template is able to display all of the data stored in the database example.
The first table shows the HEADER of the table, and the second shows data with
its respective header (see lines 17, 20, 23, and 26, with the values coming
from view.php). Line 29 shows the extraction of data by looping over
the users array from view.php to show the values of the user, ID, FIRSTNAME,
LASTNAME, and EMAIL fields (lines 32, 35, 38, and 41).
Finally, the Return button sends users back to the home page.
All of the template files (*.tpl) must go in the templates directory.
Conclusion
Working in three tiers with PHP saves repetitive work and makes for maintainable code, partly due to object oriented programming. It's easy to use the powerful Smarty and PEAR::DB_DataObject together.
Luis Yordano Cruz is a systems engineer in Trujillo PERU with more than five years of experience developing web-based applications with PHP, Java/J2EE, and JavaScript.
Return to the PHP DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 20 of 20.
-
Better Example
2005-10-14 01:00:41 bfioca [Reply | View]
This article, while helpful for learning the intricacies of DB_DataObjects and Smarty, isn't particularly useful for much more than simple projects.
For much larger scale apps, and true encapsulation of mode, view, and controllers, check out WASP
http://wasp.sourceforge.net
For those who don’t yet know, WASP is a lightweight but powerful framework written in the spirit of (but rather different than) Ruby on Rails. The purpose, really, is to utilize all of the enhancements made to PHP in version 5 to build a reusable framework for large applications.
-
Error! Help
2005-07-26 03:39:37 xfactorx [Reply | View]
Hello,
I tried out the tutorials and I had the following errors when I clicked on save and view. Here are the errors:
Notice: Constant DB_DATAOBJECT_FETCHMODE_ASSOC already defined in C:\php\pear\Db\DataObject.php on line 98
Notice: Constant DB_DATAOBJECT_INT already defined in C:\php\pear\Db\DataObject.php on line 108
Notice: Constant DB_DATAOBJECT_STR already defined in C:\php\pear\Db\DataObject.php on line 109
Notice: Constant DB_DATAOBJECT_DATE already defined in C:\php\pear\Db\DataObject.php on line 111
Notice: Constant DB_DATAOBJECT_TIME already defined in C:\php\pear\Db\DataObject.php on line 112
Notice: Constant DB_DATAOBJECT_BOOL already defined in C:\php\pear\Db\DataObject.php on line 113
Notice: Constant DB_DATAOBJECT_TXT already defined in C:\php\pear\Db\DataObject.php on line 114
Notice: Constant DB_DATAOBJECT_BLOB already defined in C:\php\pear\Db\DataObject.php on line 115
Notice: Constant DB_DATAOBJECT_NOTNULL already defined in C:\php\pear\Db\DataObject.php on line 118
Notice: Constant DB_DATAOBJECT_MYSQLTIMESTAMP already defined in C:\php\pear\Db\DataObject.php on line 119
Notice: Constant DB_DATAOBJECT_ERROR_INVALIDARGS already defined in C:\php\pear\Db\DataObject.php on line 133
Notice: Constant DB_DATAOBJECT_ERROR_NODATA already defined in C:\php\pear\Db\DataObject.php on line 134
Notice: Constant DB_DATAOBJECT_ERROR_INVALIDCONFIG already defined in C:\php\pear\Db\DataObject.php on line 135
Notice: Constant DB_DATAOBJECT_ERROR_NOCLASS already defined in C:\php\pear\Db\DataObject.php on line 136
Notice: Constant DB_DATAOBJECT_ERROR_INVALID_CALL already defined in C:\php\pear\Db\DataObject.php on line 137
Notice: Constant DB_DATAOBJECT_WHEREADD_ONLY already defined in C:\php\pear\Db\DataObject.php on line 143
Fatal error: Cannot redeclare class db_dataobject_overload in C:\php\pear\Db\DataObject.php(215) : eval()'d code on line 2
somebody help pls. Btw did anybody got this to work?
-
This is...
2005-07-03 19:43:12 gremlinx [Reply | View]
..quite literally trash.
The author has includes under the webroot.
(It would be best if your application directory sat PARALLEL to your template folder, include folders and class files. Also a /conf & a /ini directory PARALLEL to the application pages would be logical.)
He encourage illogical include practices.
(Smarty should not need to be copied to your application directory. Easier.. toss it in a folder under your php install and add the path to your include_path setting in php.ini.)
Second encouraging a user to turn register globals on instead of fixing your code is downright retarded. As is, your examples don't work on any system with short tags off and register globals off.. which in my experience is almost all hosts.
If anyone wants a zip copy of this in a working fashion with .sql dumps and the table schemas feel free to email me @ Abba.Bryant AT gmail.com
-
This is...
2005-11-26 23:20:39 infolock [Reply | View]
ignorance is bliss...
obviously, this article isn't only meant for advanced users and production sites. It's meant as a stepping stone, not as a "DO THIS AND ONLY THIS".
Retards like you are why I never post tutorials. Because you are just looking for anything to say "HEY, LOOK AT ME! I can bash people without even considering my thoughts!"
Write an article, then come back. Because when you do, you can rest-assure that I will be bashing you homie.
-
Not very infomative
2005-05-23 23:51:31 dxxchung [Reply | View]
Thank you for such excellent work.
I am a beginner. This is a very good case. I have not seen any other tutorials that chain up the input, view, save sreens and the codes together using php and mysql. But I cannot follow some of the codes not in linux format in autobuilding a database schema ie generating User.php. All I have to say is that your work is very informative. -
Not very infomative
2005-05-31 23:57:14 dxxchung [Reply | View]
I finally found out what had been missing in your model.
Firstly, add the following lines to pass variables in save.php
$x=$_POST["x"];
$y=$_POST["y"];
$z=$_POST["z"];
Secondly, add a program, which I called schemagen.php.
<?php
//
// Builds the DataObjects classes
$_SERVER['argv'][1] = 'example.ini';
require_once 'DB/DataObject/createTables.php';
?>
I have seen this article translated and posted in simplified Chinese in several sites. Anyway, your model will become the backbone of my first commercial project.
-
Not very infomative
2005-05-05 14:53:19 mattneedles [Reply | View]
This article is vague and not very informative. The author dwells on displaying header, footer, cancel button but does not clearly state how the initial setup is done. For that mattter, "Simplify Business Logic with PHP DataObjects" by Darryl Patterson is more informative and easy to understand:
http://www.onlamp.com/pub/a/php/2004/08/05/dataobjects.html
Is there a way to unplug the DB object as it is only an abstraction layer for the database to address situations where the database vendor is changed in future? The chances of switching the database is mostly nil and the additional DB layer only slows down the process. Despite the DB_DataObjects being built on top of DB object, it seems like we still have to construct our own result set in the above example which is redundant:
$user->find();
while ($user->fetch()) {
$smarty->append('users', array(
'ID' => $user->user_Id,
'FIRSTNAME' => $user->first_Name,
'LASTNAME' => $user->last_Name,
'EMAIL' => $user->email,
));
I wish this article on DB_DataObjects was written by Darryl Patterson as he said he might write it in future. -
Not very infomative
2005-05-06 07:58:54 lycruzc [Reply | View]
Excuse me, but you cannot say that is vague this article, for which I see You are a novice in PHP and does not know : The Framework PEAR, Smarty and the Development in Three Tier. -
Not very infomative
2005-05-06 14:34:38 mattneedles [Reply | View]
You haven't any idea as to who I'm, what I do or what I've achieved with Smarty and 3-tier architecture. I've successfully unplugged the DB from DB_DataObjects to use raw PHP functions for MySQL database access for improving performance on high-traffic sites.
Forget about the PEAR framework, Smarty, 3-tier... how about the basic PHP? Advising another user to set:
register_globals=OFF => register_globals= ON
does not make you a guru in PHP in the first place.
Here is the usage documentation on DB_DataObjects:
http://pear.activeventure.com/package/package.database.db-dataobject.html
I wonder who has approved your article on OnLamp.
Excuse you! -
Not very infomative
2007-01-31 07:14:21 greenphpcoder [Reply | View]
Thats brill but why do all that, everyone knows that HTML, its the future! -
Not very infomative
2005-11-26 23:24:27 infolock [Reply | View]
"You haven't any idea as to who I'm, what I do or what I've achieved with Smarty and 3-tier architecture. I've successfully unplugged the DB from DB_DataObjects to use raw PHP functions for MySQL database access for improving performance on high-traffic sites."
If you did what you are saying you did, you obviously are a novice. Novices use the approach of raw php functinos for mysql database access. Thus why you get haxx0red by the kiddies.
You remind me of gremlin. He seems to have the same mentality as you : mind-numbing.
-
Sorry to be picky but...
2004-12-28 02:59:06 HarryF [Reply | View]
Like the article overall and great to see layered application design being encouraged. Have to scratch some itches though...
Please modify the examples on the second page so they use full PHP processing instruction declarations i.e.;
<?php
</code>
not;
<?
</code>
Inphp.inithere's an option called "short_open_tag". The later form;<?</code> is only possible when short_open_tag is On, so the examples will not work for those that have it switched off, potentially reducing the portability of the code, across different PHP installations.
Also include, require, require_once etc. are language constructs not functions so although the parenthesis is allowed, it's generally better form to write;
include 'somefile.php';
It's also better practice (ignoring any performance issues) to always use require_once when including class files, to take care of the situations where, say, multiple child classes in seperate files all attempt to include the same parent class script.
-
use _POST for x, y, z
2004-12-15 10:50:59 yasheshb [Reply | View]
in the file save.php use _POST to reference the form variables. using $x, $y, $z did not work for me.
5 $user->first_Name = $_POST['x'];
6 $user->last_Name = $_POST['y'];
7 $user->email = $_POST['z'];
-
use _POST for x, y, z
2004-12-15 15:41:08 lycruzc [Reply | View]
Hi friend, for that work without _POST; You should activate the var :
register_globals=OFF => register_globals= ON
This variable this in the file of configuration of PHP (php.ini).



First I wonder what happened to the example database schema, I had to manually create it when we can read in the "Creating the database" section : « Don't worry about the schema yet; that will come later. ». Here is the database schema exported from PhpMyAdmin :
CREATE TABLE `user` (`user_Id` int(11) NOT NULL auto_increment,
`first_Name` varchar(30) NOT NULL default '',
`last_Name` varchar(40) NOT NULL default '',
`email` varchar(100) NOT NULL default '',
PRIMARY KEY (`user_Id`)
) TYPE=MyISAM AUTO_INCREMENT=5 ;
Next I found the HTML code a bit messy. Templates should include a global header and footer, and some developers would probably enjoy a cleaner code, without the obsolete tags and tables (even if XHTML/CSS is out of topic). There's even JavaScript code when hyperlinks should be used.
I also think using "magic" variable names is inappropriate : x and data1 instead of first_Name for example. I think explicit names like first_Name should be used all along, from the database table fields and PHP variables to HTML attributes. It's like magic numbers, magic variable names should be avoided at all cost (3.14 instead of PI for example).
Let's just say the article is magic :).