100% found this document useful (2 votes)
3K views

Oracle and PHP

Como usar Oracle con Zend Framewrok

Uploaded by

pablofmorales
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (2 votes)
3K views

Oracle and PHP

Como usar Oracle con Zend Framewrok

Uploaded by

pablofmorales
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Zend Background Paper

Zend Technologies
Library Zend Whitepaper PHP and Oracle

PHP and Oracle


How to develop a application in PHP using Zend Framework, Oracle Database and Core for Oracle
Author: Gaylord Aulke, Zend Technologies GmbH

Table of Contents Page


Preface 1
Installing Zend Core for Oracle 1
Installing Zend Framework 1
Prerequisites 1
Download and unpack 1
Configure PHP and web server 2
Building a Zend Framework application skeleton 2
Bootstrap file 2
Directory structure 2
Default Action Controller 2
Mapping URL’s to controllers and Action Methods 3
More Action Controllers 3
Creating a Model 3
Zend Framework overall Structure
Connecting the DB 3
Using an external configuration file 4
Separating layout from application logic using View 5 Installing Zend Core for Oracle
The HR Application (example) 6 Please refer to the “PHPfest Tutorial: Oracle Database 10g Express
Listing all Employees 7 Edition and Zend Core for Oracle” for installation instructions. On
Editing an Employee 7 Windows, just start the setup.exe after downloading, answer some
Epilogue 10 questions right and lean back. Zend Core for Oracle will install on
existing Apache and IIS web servers. It also brings its own Apache
Preface for a complete new installation if needed.
Zend Core for Oracle is a Zend certified and supported version of
the open source PHP. It uniquely delivers a seamless out-of-the- Installing Zend Framework
box experience by bundling all the necessary drivers and third Prerequisites
party libraries to work with the database of your choice. It can - Apache with mod_rewrite required or IIS with ISAPIRewrite
be downloaded at: http://www.zend.com/downloads Software3
- PHP 5.1.4 or later
Zend Framework1 is an open source framework for PHP. It helps - activated OCI8-Extension
to structure PHP based web applications in a good way and comes (PHP with OCI8 Extension comes with the Zend Core for Oracle)
with a variety of libraries and tools that increase developer
efficiency. The most important development guidelines of Zend Download and unpack
Framework were two principles: To install Zend Framework, just download the newest zip package
1. extreme simplicity from http://framework.zend.com and extract it to a directory
2. use-at-will architecture that is readable by the web server process, so PHP applications
can include the classes in their include_path. A good choice for
In addition to a MVC implementation and lots of libraries, Zend the location of the framework could be:
Framework defines common coding standards2 including naming
conventions and a package-like directory structure. /opt/ZendFramework/
... on linux systems (according to FHS)4
Zend Framework is open source and licensed under the new BSD /Library/Zend Framework
license. Therefore it can be integrated even in commercial ... on Mac OS X
applications without the constraints imposed by other licenses C:\Program Files\Zend Technologies\Zend Framework\
such as the GPL. Specifically, your project is not forced to adopt ... on Windows
an open source license.
(Currently install packages for different operating system types
are under development, but they are not available yet)

1 Zend Framework: http://framework.zend.com


2 Coding Standards: http://framework.zend.com/wiki/display/ZFDEV/PHP+Coding+Standard+(draft)
3 IIS ISAPI Rewrite Engine: http://www.isapirewrite.com/
4 File System Hierarchy Standard (FHS): http://www.pathname.com/fhs/pub/fhs-2.3.html
1
Zend Background Paper

Zend Whitepaper PHP and Oracle

Configure PHP and web server Directory Structure


After unpacking, point the PHP include_path (directive set in It is recommended that websites built with the Zend Framework
php.ini) to the lib directory of the Zend Framework installation share a common directory structure. Conforming to this structure
directory. makes your code more easily understandable by someone familiar
Example (excerpt from php.ini): with the conventions of the Zend Framework.
The suggested directory structure consists of both library directories
;;;;;;;;;;;;;;;;;;;;;;;;;
(from Zend and elsewhere) and application directories.
; Paths and Directories ;
;;;;;;;;;;;;;;;;;;;;;;;;; /app
/models
; UNIX: "/path1:/path2" /views
include_path = ".:/opt/ZendFramework/library" /controllers - where your action controllers go
; /htdocs - document root of the web server
; Windows: "\path1;\path2" /images
;include_path = ".;c:\php\includes" /styles
.htaccess - may contain rewrite rule and include_path (apache module)
There are some other ways of setting the include path for PHP.
index.php
For more information refer to
/lib - symbolic link to /opt/ZendFramwork/library
http://de.php.net/manual/en/configuration.changes.php
/Zend
/PEAR
In a MVC Application, all requests are routed to one single entry
...etc
point. For Zend Framework this is a PHP script. Typically, this
so called Controller Script would be the only PHP file inside your
Default Action Controller
web server's document root. The framework files and your
Zend Framework maps all requests to dynamic resources on the
application code should be stored outside the document root of
web server via the bootstrap file to so called Action Controllers.
the web server. They are all loaded via include directives from
These are PHP Classes that have one Method per different request
the one Controller Script that is called for every request.
they can service. The first action controller that needs to be
Typical Zend Framework URLs look like this:
present in every application is the default controller. It is called
http://myserver.com/
whenever the framework did not read a specific controller name
http://myserver.com/start
from the URL. For example it is used when the homepage of the
http://myserver.com/profile/login
application is called, i.e. only the domain name is given. The
To direct all these requests to the Controller Script, URL rewriting
user requests: http://www.myserver.com
needs to be enabled on the web server. This can be done in the
In this case, Zend Framework starts the Default Controller which
httpd.conf inside a Vhost directive or in a .htaccess file in a local
is called IndexController and calls the indexAction in this controller.
directory. For IIS please refer to http://www.isapirewrite.com.
An IndexController can be coded like this:
Assume your controller script is in the document root of your
web server and it is called index.php. Then, the rewrite rule (for
.../app/controllers/IndexController.php:
apache mod_rewrite) looks like this:
<?php
RewriteEngine On
require_once 'Zend/Controller/Action.php';
RewriteRule !\.(html|php|js|ico|txt|gif|jpg|png|css|rss|zip|tar\.gz|wsdl)$
class IndexController extends Zend_Controller_Action
/index.php
{
public function indexAction()
Building a Zend Framework Application Skeleton
{
Bootstrap File
echo 'Hello from IndexController';
After the rewrite rule is in place, the next thing needed will be
}
a Controller Script (also referred to as the “bootstrap file”) in
}
the document root of your web server:
?>
<?php
In Order to be found by the FrontController called in the bootstrap
set_include_path('.:/pathToApp/app:/pathToApp/lib');
file, the source code file must be stored in the specified controller
require_once 'Zend/Controller/Front.php';
directory (.../app/controllers in this case). The file must be
Zend_Controller_Front::run('/pathToApp/app/controllers');
named IndexController.php and it must contain a class declaration
?>
for the class IndexController. This class must extend the Framework
If not possible in the php.ini file or .htaccess files, the include Class Zend_Controller_Action (which is first included with the
path can be set using the set_include_path command in this file. require_once directive) to connect with the FrontController. The
The run method of the Controller requires the file system path Method indexAction() of this class will now be called without
to your action controllers as a string argument. The Action parameters whenever the homepage of the server is requested.
Controllers are your custom codes for doing whatever your
application is supposed to do. All the application logic will be
implemented in such Action Controller Classes.

2
Zend Background Paper

Zend Whitepaper PHP and Oracle

Mapping URLs to Controllers and Action Methods


Zend Framework generally maps the first given directory name public function init() {
to an Action Controller Name and the second directory name to $this->hrModel = new HRModel();
a Method inside this controller. When only one identifier is given }
in the URL, it is used as the controller name an the method is
set to 'index'. If no information is given in the URL, the index public function indexAction()
Method from the IndexController is used: {
echo $this->hrModel->helloWorld();
http://framework.zend.com/roadmap/future/
}
Controller: RoadmapController
}
Action : futureAction
?>

http://framework.zend.com/roadmap/ The first thing we added is the require_once in line 3. This in-
Controller: RoadmapController cludes the source file in which the Model is defined. Then, in the
Action : indexAction init() function which is called when the controller object is
created, an instance of the HRModel is made and stored in the
http://framework.zend.com/ instance variable hrModel that was previously declared. The
Controller: IndexController PHPDoc comment before the variable declaration gives the Zend
Action : indexAction Studio IDE the information needed to provide code completion
for the instance variable hrModel. After this, an hrModel object
More Action Controllers is present in the IndexController and can be used by any
Now other Action Controllers can be written and placed in the ActionMethod by referencing $this->hrModel. We try this in the
controller directory. They are all built in the same way as the indexAction: We call the helloWorld Method we have implemented
IndexController described above. For more information on making in our hrModel and output the returned value to the browser
the assignment from URLs to controllers more flexible see the using the echo command of php (later we will render all output
documentation at http://framework.zend.com via so called views to separate logic from layout but for now this
should do).
Creating a Model If we now call the home page of our web application, the output
In MVC, all the actual work the application is supposed to do is will be as follows:
implemented in a special class called 'Model' (the 'M' in MVC). Browser:
This includes all database operations. The Action Controller http://www.myserver.com/
instantiates a Model and then calls functions on it. To visualize Result:
this, let us first start with creating an empty Model class: Hello World

.../models/HRModel.php:
Connecting the DB
<?php Since our application will display database content, we will need
class HRModel { a database connection to get to the required information. As an
function helloWorld() { example we use the predefined HR schema that comes with
return 'Hello World'; Oracle XE and the normal Oracle installation as an example
} schema. (Please make sure to unlock the Oracle user called HR
} first and assign it the password hr.)
?> To connect to a DB from Zend Framework, we use a class called
DB Adapter. It can be found in the Package Zend_Db in the
Now we have a (very simple) Model with a function that returns
Framework distribution. We will also need some credentials to
something that can be output to the browser. So let us use it in
connect to the database. We assume that we use the DB on the
the Controller. Since we will probably have many methods in our
local host and login with username and password 'hr'. So where
controller that are all very likely to call methods on our Model,
do we put the connection code? Since the Model will use the DB
we instantiate the Model right at the beginning of the lifetime
connection in most of its methods, it makes sense to open a
of our controller and store it for later use in an instance variable
connection whenever the Model is instantiated. Therefore we
for the action controller object:
put the connection code into the constructor of the Model and
.../app/controllers/IndexController.php: store the connection in an instance Variable of our Model. To
check if the connection was successful, we implement a new
<?php
Method in our Model that fetches the Sysdate from the oracle
require_once('Zend/Controller/Action.php');
instance and replace our nice but useless helloWorld function
require_once('models/HRModel.php');
with it:

class IndexController extends Zend_Controller_Action


{
/**
* @var HRModel
*/
protected $hrModel;
3
Zend Background Paper

Zend Whitepaper PHP and Oracle

.../models/HRModel.php:
{
<?php
/**
require_once('Zend/Db.php');
* @var HRModel
*/
class HRModel {
protected $hrModel;
/**
* @var Zend_Db $db public function init() {
*/ $this->hrModel = new HRModel();
protected $db = null; }

public function indexAction()


function __construct() {
{
$params = array (
echo $this->hrModel->getSysDate();
'username' => 'hr',
}
'password' => 'hr',
}
'dbname' => '//localhost/XE'
?>
);
This little change now results in displaying the current date (in
$this->db = Zend_Db::factory('oracle', $params);
German format) instead of the simple Hello world message. The
$this->db->query("alter session set
output looks like this:
NLS_NUMERIC_CHARACTERS = ',.'");
Browser:
$this->db->query("alter session set
http://www.myserver.com/
NLS_DATE_FORMAT = 'dd.mm.yyyy'");
Result:
}
01.02.2007
/**
Using an external configuration file
* return the current sysdate of the oracle server
With our example model, we could successfully connect to the
*
database. In order to make the example easy to understand, we
* @return string
“hardcoded” the database credentials into the model's source
*/
code. In real world applications we do not want to do this since
function getSysDate() {
we might have different environments where the code should
$res = $this->db->fetchRow("SELECT sysdate FROM dual");
work without changes afterwards. Therefore we separate this
return $res['SYSDATE'];
kind of environment information in configuration files. Zend
}
Framework supports different methods of storing such information.
}
In this example we use the ini-file method that parses windows
?>
like ini-files with sections and parameters. This is how we integrate
Note that we needed to include the Zend DB Adapter prior to the Zend_Config_Ini Component with our existing HRModel:
using it with a require_once statement in line 2. The Model now
.../models/HRModel.php:
creates a connection to the Oracle DB in the Constructor of the
Model and stores it in the instance variable $this->db for later <?php
use. At the same time, some session variables are set for the require_once('Zend/Db.php');
oracle connection to control number and date formatting. This require_once('Zend/Config/Ini.php');
can be left out if you set the according values generally for the
class HRModel {
oracle instance. Our new function getSysDate() then uses the
/**
Oracle connection that was built in the constructor to select the
* @var Zend_Db $db
current system date from the oracle database using the fetchRow()
*/
method of the DB object in $this->db. This method sends a query
protected $db = null;
to the database and returns the first row of the result in form
of an associative PHP array. We then return the column 'SYSDATE' function __construct() {
from this array to the caller of the method. Of course, there are $config = new Zend_Config_Ini('hr.ini', 'staging');
simpler methods in PHP to determine and format the current
date. This is only to show that we can make the DB do things for $params = array (
us. Now we need to modify the IndexController to output the 'username' => $config->database->user,
result of our brand new database interaction: 'password' => $config->database->passwd,
'dbname' => $config->database->dbname
.../app/controllers/IndexController.php: );
$this->db = Zend_Db::factory('oracle', $params);
<?php
$this->db->query("alter session set
require_once('Zend/Controller/Action.php');
NLS_NUMERIC_CHARACTERS = ',.'");
require_once('models/HRModel.php'); $this->db->query("alter session set
NLS_DATE_FORMAT = 'dd.mm.yyyy'");
class IndexController extends Zend_Controller_Action }
4
Zend Background Paper

Zend Whitepaper PHP and Oracle

/** public function indexAction()


* return the current sysdate of the oracle server {
* $view = new Zend_View(array('scriptPath' =>
* @return string '<pathToMyApp>/app/views'));
*/ $view->sysdate = $this->hrModel->getSysDate();
function getSysDate() { echo $view->render('index.phtml');
$res = $this->db->fetchRow("SELECT sysdate FROM dual"); }
return $res['SYSDATE']; }
} ?>

} At first we fetch the Zend_View definition by including the


?> according source file with require_once in line 4. Then in the
indexAction, we first instantiate a View Object giving it the path
The differences to the previous version of our Model start with
where to find the view scripts (please enter the base path of
the “require_once” statement that includes the declaration of
your application instead of <pathToMyApp> there). In the next
Zend_Config_Ini. Then, before we make the DB connection in
line we assign the sysdate we got from the Model to this view
the constructor of our Model, we create a Zend_Config_Ini Object
object and then we use the view script 'index.phtml' to render
from the ini-file hr.ini that we will store in the include directory
of our app. The Zend_Config_Ini Object will filter this ini file for an output string from the data we have put into the view before.
the label 'staging' and extract all parameters that match this Note that render() does not output anything but returns a string.
filter. For detailed information on the format of the ini file and This can then be output to the browser using the echo command.
other information about Zend_Config see: To make this example complete, we need our new view script
http://framework.zend.com/wiki/display/ZFDOCDEV/4.+Zend index,phtml. It must be stored in the subdirectory 'views' of our
_Config application:
The parameters array for creating the Oracle DB adapter is now
.../app/views/index.phtml:
no longer assembled from static text but the individual settings
<html>
are taken from according parameters from the Zend_Config. The
<body>
config file looks like this:
Sysdate: <?= $this->sysdate ?>
.../app/include/hr.ini: </body>
</html>
[staging]
database.user=hr Of course this is not a very pretty example of a HTML output
database.passwd=hr page. But it shows the concept: The view script is basically a php
database.dbname=//localhost/XE script that is executed inside a method of the Zend_View object.
Therefore it can access all resources of Zend_View referencing
Separating Layout from application logic using Views $this->. An example is the sysdate that was put into the view
The last element of MVC that we did not introduce yet is the object by the controller before the view script was executed
View. This Component renders the data we got from the model during the call to $view->render(). Sysdate is an instance variable
into HTML. In an MVC application, the Model gathers data and of the view object and thus can be referenced using $this-
triggers transactions, the Controller controls user interaction and >sysdate. Since the php interpreter is in HTML mode when the
page flow and the View is responsible for the output of data in view script is executed, it treats all content of the view script
a nice and shiny format. The Zend_View is a class with lots of as HTML until it finds an opening PHP tag (<?). Generally it is
helpers for the output of plain HTML and Forms. The Controller possible to embed any PHP code in a view script but it is
Methods can create such a view, populate it with dynamic data recommended to use as little php as possible there. To output
they want to display on the page and then hand this over to a variables from the viw, the short print notation of php can be
template like view script. We illustrate this mechanism using the used (as in the example). The format of this notation is:
IndexAction in our IndexController:
<?= <expression> ?>
.../app/controllers/IndexController.php:
... while expression can be any valid php expression including
<?php calls to php internal functions etc. In this case we just output
require_once('Zend/Controller/Action.php'); the contents of the instance variable sysdate. When we now call
require_once('models/HRModel.php'); our home page again, we still get:
require_once('Zend/View.php'); Browser:
http://www.myserver.com/
class IndexController extends Zend_Controller_Action
Result:
{
Sysdate: 01.02.2007
/**
In contrast to the output we have seen before, result page is
* @var HRModel
now well formatted HTML with start and end tags for HTML and
*/
BODY.
protected $hrModel;

public function init() {


$this->hrModel = new HRModel();
}
5
Zend Background Paper

Zend Whitepaper PHP and Oracle

The HR Application We just wrapped the complete Query in a Method declaration


We now want to write a small Application that lists the employee and a call to $this->db->fetchAssoc(). The result of fetchAssoc
records from the HR database that comes with the default is the desired list in form of a list of associative arrays (one for
installation of Oracle 10g or Oracle XE. each row).
Now we call this new method from our indexAction and store the
Listing all Employees resulting array in the View Object:
First we need a Controller Action that fetches the list from the .../app/controllers/IndexController.php:
db and outputs the result to the browser. To make things as
simple as possible, we use the indexAction from the IndexController <?php
for this. The user will therefore be prompted with the employee require_once('Zend/Controller/Action.php');
list when he starts the application by calling the homepage. require_once('models/HRModel.php');
The SQL query to fetch all employees and format them nicely is require_once('Zend/View.php');
given as follows: class IndexController extends Zend_Controller_Action
SQL: {
SELECT employee_id, substr(first_name,1,1) || '. '|| last_name as /**
employee_name, * @var HRModel
hire_date, to_char(salary, '9999G999D99') as salary, */
nvl(commission_pct,0)*100 as commission_pct, protected $hrModel;
d.department_name, j.job_title public function init() {
FROM employees e, departments d, jobs j $this->hrModel = new HRModel();
WHERE e.department_id =d.department_id and e.job_id = j.job_id }
ORDER BY employee_id asc
public function indexAction()
As a first step, we integrate this query in our HR Model and return {
the resulting rows in form of an array of result rows. Each of $view = new Zend_View(array('scriptPath' =>
these rows is an associative array itself. <pathToMyApp>/app/views'));
.../models/HRModel.php: $view->employeeList = $this->hrModel->queryAllEmployees();
$view->sysdate = $this->hrModel->getSysDate();
<?php
echo $view->render('index.phtml');
require_once('Zend/Db.php');
}
require_once('Zend/Config/Ini.php');
}
class HRModel { ?>
/** Now we have the result in our View Object. The next step would
* @var Zend_Db $db
be to display the result in the View Script index.phtml:
*/
protected $db = null; .../app/views/index.phtml:

function __construct() { <html>


... <head>
} <link rel="stylesheet" type="text/css" href="/style.css" />
... </head>
<body>
/** Sysdate: <?= $this->sysdate ?>
* returns a list of all employees in an assoc. array <table>
* <tr>
* @return array
<th>Employee<br>ID</th>
*/
<th>Employee<br>Name</th>
public function queryAllEmployees() {
return $this->db->fetchAssoc( <th>Job<br>Title</th>
"SELECT employee_id, <th>Hiredate</th>
substr(first_name,1,1) || '. '|| last_name as employee_name, <th>Salar[y</th>
hire_date, to_char(salary, '9999G999D99') as salary, <th>Commission<br>(%)</th>
nvl(commission_pct,0)*100 as commission_pct, <th>Department</th>
d.department_name, j.job_title </tr>
FROM employees e, departments d, jobs j <?php
WHERE e.department_id =d.department_id AND e.job_id // Write one row per employee
= j.job_id foreach ($this->employeeList as $emp):
ORDER BY employee_id asc");
extract($emp);
}
echo <<<END
}
?>

6
Zend Background Paper

Zend Whitepaper PHP and Oracle

<tr> statement. The bracket notation could also be used here but the
<td align="right">$EMPLOYEE_ID</td> alternative notation seems better inside templates.
<td>$EMPLOYEE_NAME</td> The foreach block is executed once per row in the employeeList
<td>$JOB_TITLE</td> variable, meaning once per result row. Inside the block, the
<td>$HIRE_DATE</td> current row can be referenced via the variable $emp. The
<td align="right">$SALARY</td> individual columns of the result row could now be referenced by
<td align="right">$COMMISSION_PCT</td> using their names as an index to the array $emp. For example
<td align="right">$DEPARTMENT_NAME</td> $emp['EMPLOYEE_NAME'] would reference the name column from
</tr> the current row.
END; To make references to the fields of the result row simpler, we
endforeach; use the extract() command of php on $emp. This command creates
?> one local variable for every key in the given array and copies the
</table> associated value in this new variable. Instead of using
</body> $emp['EMPLOYEE_NAME'] it is then possible to reference the name
</html> by simply using $EMPLOYEE_NAME.
After the extract command we use the HEREDOC syntax of PHP
In addition to the basic view script that only displays the sysdate, to echo one table row to the browser. This notation allows multi
some changes were introduced here. At first, we added a link to line strings in which variables are automatically replaced by their
a style sheet named style.css that improves the layout a little: values. Also, quotation marks and other special characters can
.../htdocs/styles.css: be used without the need to escape them inside a string. The
string to echo ends with and END marker at the beginning of a
body { new line. Calling our home page now results in a employee list:
background: #CCCCFF; Browser:
color: #000000; http://www.myserver.com/
font-family: Arial, sans-serif; Result:
}
h1 {
border-bottom: solid #334B66 4px;
font-size: 160%;
}
table {
width: 100%;
font: Icon;
border: 1px Solid ThreeDShadow;
background: Window;
color: WindowText;
}
td {
padding: 2px 5px;
vertical-align: top;
text-align: left;
}
th {
border: 1px solid; Editing an Employee
border-color: ButtonHighlight ButtonShadow Now that we have a list, we might want to display a record in
ButtonShadow ButtonHighlight; detail and edit its contents. For example we could want to add
cursor: default; a commission or to change department, job title or telephone
padding: 3px 4px 1px 6px; number. To do so, we first need a link to a new action called
background: ButtonFace; editForm in the List. When the user clicks on the id of an employee,
} he gets to a form with the details of the according user. So first
Further, we integrated a HTML table that will show the result we add the new link. This can be done in the View Script:
list. This table has a first row with column titles in plain HTML.
Then for the output of the actual row content, we switch to PHP
mode in the view script (<?php). Using the foreach control structure
of PHP, we iterate over the employeeList array which had been
stored in the view object by the Controller Action before.
To make the loop more visible inside the HTML fragments in this
file, we do not use the normal bracket notation to denote the
foreach-block but we use an alternative format. This format
starts the block with a colon and ends it with the endforeach

7
Zend Background Paper

Zend Whitepaper PHP and Oracle

is coming from outside the application should go through “white


.../app/views/index.phtml:
list” input filters. That means, only values that are definitely
<html>
legal values for the according variable should be accepted.
...
Everything else must be filtered out or trigger an error. The die()
<?php
command tells php to stop the execution of the program at once
// Write one row per employee
after displaying the contents of the first argument of the die()
foreach ($this->employeeList as $emp):
function. In our case, it is only a debug output to show that the
extract($emp);
method was called and the value of the id field was transferred
echo <<<END
correctly.
<tr>
Now we have created a new action that can be called by clicking
<td align="right"><a href="/index/edit/id/
on the Employee-ID in the employee list. Clicking on the id of
$EMPLOYEE_ID">$EMPLOYEE_ID</a></td>
the first user in the list generates the following output:
<td>$EMPLOYEE_NAME</td>
edit called for id:100
<td>$JOB_TITLE</td>
Now we want to replace the die() call with something useful:
<td>$HIRE_DATE</td>
The form to edit the profile of an employee. To do this, we need
<td align="right">$SALARY</td>
to accomplish a number of tasks:
<td align="right">$COMMISSION_PCT</td>
1. fetch the record of the employee from the database
<td align="right">$DEPARTMENT_NAME</td>
2. fetch the option lists for departments and job names from
</tr>
related tables to display them as choices in dropdown lists
END;
3. display a form with different input fields with the data in
endforeach;
them pre filled
?>
</table> We start with a function to fetch data from the database. This
</body> function is implemented in the HRModel:
</html>
.../app/HRModel.php:
The new link calls the method editAction() in our IndexController.
<?php
But what does the rest of the URL mean? To edit an employee
we need to select which record to edit. We do that by transferring require_once ...
the EMPLOYEE_ID along in the URL. Usually this is done with GET class HRModel {
parameters in the style ...
'http://www.myserver.com/index.php?id=xyz'. To make the URLs /**
prettier, Zend Framework offers another option to pass values * find a specific employee by his employee_id and return
to the action controllers: If controller name and action name are * the data in an assoc. array.
both given, all path elements suceeding the action name are
*
handled as key/value pairs for parameter passing. Therfore the
* @param int $eid
URL in our new link is interpreted in the following way:
* @return array
example URL: “/index/edit/id/100”
*/
Controller: IndexController
function findRecord($eid) {
Action: editAction
$myvars['EMPID'] = $eid;
Parameter1: id=100
$res = $this->db->fetchAssoc("SELECT employee_id, first_name,
What we need next is a new action method in the indexController.
last_name,
It looks like this:
email, hire_date, salary, (nvl(commission_pct,0)*100) as
.../app/controllers/IndexController.php
commission_pct,
<? department_id, job_id
require_once ... FROM employees
class IndexController extends Zend_Controller_Action WHERE employee_id = :empid", $myvars);
{ return $res[$eid];
... }
public function editAction() { }
$id = (int)$this->_getParam('id'); ?>
die('edit called for id:'.$id);
It should be easy to replace the die() in the controller by a call
}
to this function and a var_dump() of the returned array. This
}
way the function can be tested before we continue. This is skipped
?>
here.
By calling the method $this->_getParam($name) of the Action The next we need to do is to store the information obtained from
Controller, our new method obtains the value of the id passed the Model in the view object and write a view script to render
in the URL as mentioned above. For security reasons, we cast a form for us that has these values as default values in the form
the returned value to an integer. This eliminates all characters elements. So at first we modify our action method:
that are not digits and therefore makes attacks such as Cross Site
Scripting and SQL injection impossible. Note that all data that
8
Zend Background Paper

Zend Whitepaper PHP and Oracle

.../app/controllers/IndexController.php: At first, we switch to PHP mode in this view script to extract the
associative array from $this->employeeDetail into the local scope.
<?
This way, all the different fields of the currently edited record
require_once ...
are accessible via variables with the name of the according DB
class IndexController extends Zend_Controller_Action
field (as seen already in the employeeList). The we start with
{
linking our style sheet again and opening a normal HTML form.
...
The form action will be index/save, a new action that we must
public function editAction() {
integrate in our IndexController. The rest of the page is all like
$id = (int)$this->_getParam('id');
a normal HTML form with the exception that all the input fields
$view = new Zend_View(array('scriptPath' =>
are generated dynamically via so called View Helpers. These
<pathToMyApp>/app/views'));
helpers are a library of methods that the Zend_View provides for
$view->employeeDetail = $this->hrModel->findRecord($id);
rendering certain HTML tags. In this example we use $this-
echo $view->render('edit.phtml');
>formHidden() to generate a hidden field and $this->formText()
}
to generate normal text input fields. The first parameter to these
}
Helpers is always the name of the input field and the second
?>
parameter is the current value. Information about other field
The action method now stores the result of the findRecord call types can be obtained from the Zend Framework Website.
in the view object and then uses the view script called 'edit.phtml' Now we code the saveAction to store the changed values in the
to render the form. Now we code edit.phtml: database. This is done again in the IndexController. In order to
do this we must first add an update function to the hrModel. This
.../app/views/edit.phtml:
will take an EMPLOYEE_ID and an associative array of fieldnames
<?php and values and generate an update query.
extract($this->employeeDetail);
.../app/models/HRModel.php
?>
<HTML> <?php
<head> require_once...
<link rel="stylesheet" type="text/css" href="/style.css" /> class HRModel {#
</head> ...
<body> /**
<form method="post" action="/index/save"> * update all fields that are present in the assoc array
<?= $this->formHidden('EMPLOYEE_ID',$EMPLOYEE_ID) ?> * $row for the employee given in $eid
<table> *
<tr> * @param int $eid
<td>First Name</td> * @param array $row
<td><?= $this->formText('FIRST_NAME',$FIRST_NAME) ?></td> * @return int Number of affected rows
</tr> */
<tr> public function update($eid, $row) {
<td>Last Name</td> $where = $this->db->quoteInto('EMPLOYEE_ID = ?', $eid);
<td><?= $this->formText('LAST_NAME',$LAST_NAME) ?></td> return $this->db->update('employees', $row, $where);
</tr> }
<tr> }
<td>E-Mail</td> ?>
<td><?= $this->formText('EMAIL',$EMAIL) ?></td>
To accomplish this task, we use the update function of the
</tr>
Zend_DB Adapter. It requires a table name, an associative array
<tr>
of key/value pairs for the updated values and a where clause to
<td>Hiredate</td>
determine which records to update. The where clause must first
<td><?= $this->formText('HIRE_DATE',$HIRE_DATE) ?></td>
be generated by inserting the given employee-id into a query
</tr>
fragment with placeholders. The where clause is generated this
<tr>
way to enable the DB Adapter to quote the value of $eid correctly
<td>Salary</td>
for the given database. This prevents SQL injection attacks in the
<td><?= $this->formText('SALARY', $SALARY) ?></td>
where clause. The other values are quoted in the update method
</tr>
of the DB adapter.
<tr>
After we have added the needed functionality to the Model, we
<td>Commission (%)</td>
can now extend our IndexController to fetch the data from the
<td><?= $this->formText('COMMISSION_
HTML form, store it in the array that the update function needs
PCT',$COMMISSION_PCT) ?></td>
and call the update function in the Model:
</tr>
</table>
<input type="submit" value="Save" name="save">
<input type="submit" value="Cancel" name="cancel">
</form>
</body>
</HTML>
9
Zend Background Paper

Zend Whitepaper PHP and Oracle

.../app/controllers/IndexController.php Epliogue
<? We have seen in this session how to install Zend Framework and
require_once ... how to build a simple web application with it based on the HR
class IndexController extends Zend_Controller_Action schema that comes with every Oracle installation as an example
{ database schema. Our sample application lists all employees and
... offers a way to edit and save employee records with a simple
function saveAction() { form. This shows some of the basic functions and components of
// read input variables (should be checked in real application) Zend Framework. To turn this rough example into a usable
$row = array(); application, a number of additional things would be needed:
$row['FIRST_NAME'] = $_POST['FIRST_NAME'];
$row['LAST_NAME'] = $_POST['LAST_NAME']; - First of all the save method needs to be extended to do input
$row['EMAIL'] = $_POST['EMAIL']; validation on the submitted fields.
$row['HIRE_DATE'] = $_POST['HIRE_DATE']; - Some fields from the database were left out in this example
$row['SALARY'] = $_POST['SALARY']; application because they require some more coding. These
$row['COMMISSION_PCT'] = are the fields DEPARTMENT_ID and JOB_ID which should be
number_format($_POST['COMMISSION_PCT']/100,2,',','.'); implemented as drop down boxes with all rows from the
$this->hrModel->update($_POST['EMPLOYEE_ID'],$row); according database tables as options.
$this->indexAction(); - There is a trigger in the database that requires to update the
}} field HIRE_DATE to the current date whenever JOB_ID or
?> DEPARTMENT_ID are changed. This logic would also need to
be implemented.
Please note that this action contains no input filtering or validation. - Apparently, a function to add new Employees would be needed
In a real world application you would use the Zend_Validate and and a delete function would also make sense.
Zend_Filter or other components to check all the data fields from - The structure could be further optimized by extracting the
the $_POST array with a white list approach before using them SCRIPT_PATH variables from the source code lines in which
in the application to prevent hacking. And also you would want view objects are instantiated. These path information as well
to check if the values submitted by the user and re-display the as the Controller Path in the index.php should be taken from
form with according error message if the user entered invalid an ini file.
data or left required fields blank. This has been left out here to
keep the example simple. In the current preview release of Zend Although there is much room for improvement, this little example
Framework there is no standard form component in Zend shows how a structured PHP application can be built with the
Framework yet that helps you with this part. Such a component help of Zend Framework. The standard application structure and
is under development and will be available in future versions of naming conventions help to build the application in the right
Zend Framework. After copying all input values from the POST way. This gives other developers the chance to start quickly into
request to the new associative array $row, the action method application development when they join the project later and
passes this array along with the EMPLOYEE_ID to the update makes maintenance and extending the project much easier and
Method of the hrModel. After a successful update the index action more efficient.
is called which results in re-displaying the Employee-List.
For further details about Zend Framework look at
http://framework.zend.com

10
Zend Background Paper

Zend Whitepaper PHP and Oracle

About Zend Technologies


Zend Technologies Inc., the PHP Company, is the leading provider of products and services for developing, deploying and managing business-critical
PHP applications. PHP is used by more than twenty-two million Web sites and has quickly become the most popular language for building dynamic
web applications. www.zend.com

ZEND: The holistic approach to PHP


• Application management and availability with Zend PlatformTM
• Development of PHP applications with Zend StudioTM, the leading development environment for PHP
• Certified and officially supported PHP installations with Zend CoreTM
• Access to expertise of leading PHP experts with Zend Professional ServicesTM
• Improved PHP knowledge through Zend TrainingTM offers
• Protection of intellectual property and source code and administration of licensing models with Zend GuardTM
• The certified and manufacturer-supported collection of PHP components and PHP libraries – Zend FrameworkTM
• First class 24/7 support via the Zend NetworkTM

Corporate Headquarters: Central Europe: International: © 2007 Zend Corporation.


Zend and Zend Platform are registered
Zend Technologies, Inc. Zend Technologies GmbH Zend Technologies, Ltd. trademarks of Zend Technologies, Ltd.
19200 Stevens Creek Blvd. Bayerstrasse 83 12 Abba Hillel Street All other trademarks are the property
www.zend.de Cupertino, CA 95014 80335 Munich, Germany Ramat Gan, Israel 52506 of their respective owners.
Tel: 1-888-PHP-ZEND Tel: +49-89-516199-0 Tel: 972-3-753-9500
0220-M-WP-0207-R1-EN
1-888-747-9363 Fax: +49-89-516199-20 Fax: 972-3-613-9501
Fax: 1-408-253-8801 E-Mail: [email protected]

UK: Italy: France :


Zend Technologies Zend Technologies Zend Technologies SARL
50 Basing Hill Largo Richini 6 5, Rue de Rome, ZAC de Nanteuil
London NW11 8TH, United 20122 Milano, Italy 93110 Rosny sous Bois, France
Kingdom Tel.: +39 02 5821 5832 Tel : +33 1 4855 0200
Tel.: +44 20 8458 8550 Fax: +39 02 5821 5400 Fax : +33 1 4812 3132
Fax: +44 20 8458 8550

You might also like