1. Before use database we must configurate database information first.
We can use config.ini file containing the DB info. And use function Zend_Config_Ini() to get the file content.
config.ini file:

Code
[default]
; Database Settings
db.adapter = PDO_MySQL ; A Zend_Db adapter name
db.dbname = zend_study
db.hostname = localhost
db.username = pma
db.password = 123456
usually we will use Initializer.php file to do all initialization work.
Here is two functions about configurate server info and intialize DB.

Code
1
public function initServerConfig()
2
{
3
include_once 'Zend/Config/Ini.php'; // this is ZEND library file.
4
$ServerConfig = new Zend_Config_Ini($this->_root . '/config/config.ini', 'default'); // the first parameter is the directory of config.ini file
5
Zend_Registry::set('ServerConfig', $ServerConfig);
6
}
7
8
public function initDb()
9
{
10
include_once 'Zend/Db.php'; // ZEND library file.
11
include_once 'Zend/Db/Table/Abstract.php'; // ZEND library file.
12
13
$ServerConfig = Zend_Registry::get('ServerConfig'); // get configuration data
14
15
$db = Zend_Db::factory($ServerConfig->db->adapter,
16
array('host' => $ServerConfig->db->hostname, 'username' => $ServerConfig->db->username, 'password' => $ServerConfig->db->password, 'dbname' => $ServerConfig->db->dbname));
17
//create an instance of an Adapter, it's same as Zend_Db::factory('PDO_MySQL', array('host' => 'localhost', 'username' => 'pma', 'password' => '123456', 'dbname' => 'zend_study'));
18
// the second parameter of function factory() is an array containing :
19
// host: a string containing a hostname or IP address of the database server.
20
// username: account identifier for authenticating a connection to the RDBMS server.
21
// password: account password credential for authenticating a connection to the RDBMS server.
22
// dbname: database instance name on the RDBMS server.
23
// port: some RDBMS servers can accept network connections on a administrator-specified port number. The port parameter allow you to specify the port to which your PHP application connects, to match the port configured on the RDBMS server.
24
// options: this parameter is an associative array of options that are generic to all Zend_Db_Adapter classes.
25
// array(Zend_Db::CASE_FOLDING => Zend_Db::CASE_UPPER); the case of string keys in query result sets, Zend_Db::CASE_NATURAL (the default), Zend_Db::CASE_UPPER, Zend_Db::CASE_LOWER
26
// array(Zend_Db::AUTO_QUOTE_IDENTIFIERS => true); default value is true, it identifiers like table names, column names, and even aliases are delimited in all SQL syntax generated by the Adapter object, if setted to be false, should use quoteIdentifier() method to do the same thing.
27
// driver_options: this parameter is an associative array of additional options that are specific to a given database extension. One typical use of this parameter is to set attributes of a PDO driver. array( PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true );
28
// dapterNamespace: names the initial part of the class name for the adapter, instead of 'Zend_Db_Adapter'. Use this if you need to use the factory() method to load a non-Zend database adapter class.
29
30
31
if($this->_env == 'test' || $this->_env == 'development') // $this->_env value is 'test' or 'development' when project isn't done, change to 'production' parameter after done
32
{
33
$db->getProfiler()->setEnabled(true);
34
// turn on profile. Profiles include the queries processed by the adapter as well as elapsed time to run the queries, allowing inspection of the queries that have been performed. below this function is a piece of code about profile.
35
}
36
37
Zend_Db_Table_Abstract::setDefaultAdapter($db); //设置table类默认使用的数据库
38
Zend_Registry::set('db', $db);
39
$db->query("SET NAMES 'utf8'");
40
}
Using Profile:
--getTotalNumQueries() returns the total number of queries that have been profiled.
--getTotalElapsedSecs() returns the total number of seconds elapsed for all profiled queries.
--getQueryProfiles() returns an array of all query profiles.
--getLastQueryProfile() returns the last (most recent) query profile, regardless of whether or not the query has finished (if it hasn't, the end time will be null)
--clear() clears any past query profiles from the stack.
--getQuery() returns the SQL text of the query. The SQL text of a prepared statement with parameters is the text at the time the query was prepared, so it contains parameter placeholders, not the values used when the statement is executed.
--getQueryParams() returns an array of parameter values used when executing a prepared query. This includes both bound parameters and arguments to the statement's execute() method. The keys of the array are the positional (1-based) or named (string) parameter indices.
--getElapsedSecs() returns the number of seconds the query ran.

Code
1
$profiler = $db->getProfiler();
2
$db->query('select * from user');
3
$query = $profiler->getLastQueryProfile();
4
5
$totalTime = $profiler->getTotalElapsedSecs();
6
$queryCount = $profiler->getTotalNumQueries();
7
$longestTime = 0;
8
$longestQuery = null;
9
10
foreach ($profiler->getQueryProfiles() as $query) {
11
if ($query->getElapsedSecs() > $longestTime) {
12
$longestTime = $query->getElapsedSecs();
13
$longestQuery = $query->getQuery();
14
}
15
}
16
17
echo 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds<br />';
18
echo 'Average query length: ' . $totalTime / $queryCount . ' seconds<br />';
19
echo 'Queries per second: ' . $queryCount / $totalTime . "<br />";
20
echo 'Longest query length: ' . $longestTime . "<br />";
21
echo "Longest query: \n" . $longestQuery . "<br />";
2. Zend_Db_Table
usually we will create a table class extends Zend_Db_Table_Abstract can do all execution inside the class
Here we have four DB tabls, they are associated, so when we create these table class, we must define their relationships

Code
1
CREATE TABLE accounts (
2
account_name VARCHAR(100) NOT NULL PRIMARY KEY
3
);
4
5
CREATE TABLE products (
6
product_id INTEGER NOT NULL PRIMARY KEY,
7
product_name VARCHAR(100)
8
);
9
10
CREATE TABLE bugs (
11
bug_id INTEGER NOT NULL PRIMARY KEY,
12
bug_description VARCHAR(100),
13
bug_status VARCHAR(20),
14
reported_by VARCHAR(100) REFERENCES accounts(account_name),
15
assigned_to VARCHAR(100) REFERENCES accounts(account_name),
16
verified_by VARCHAR(100) REFERENCES accounts(account_name)
17
);
18
19
CREATE TABLE bugs_products (
20
bug_id INTEGER NOT NULL REFERENCES bugs,
21
product_id INTEGER NOT NULL REFERENCES products,
22
PRIMARY KEY (bug_id, product_id)
23
);

Code
1
class Accounts extends Zend_Db_Table_Abstract
2
{
3
protected $_name = 'accounts';
4
protected $_dependentTables = array('Bugs'); // parent table 父表, List the class name for each dependent table
5
}
6
7
class Products extends Zend_Db_Table_Abstract
8
{
9
protected $_name = 'products';
10
protected $_dependentTables = array('BugsProducts');
11
}
12
13
class Bugs extends Zend_Db_Table_Abstract
14
{
15
protected $_name = 'bugs';
16
17
protected $_dependentTables = array('BugsProducts');
18
19
protected $_referenceMap = array( //dependent table 子表, define reference rules
20
'Reporter' => array( // rule name
21
'columns' => 'reported_by', //A string or an array of strings naming the foreign key column name(s) in the dependent table.
22
'refTableClass' => 'Accounts', //The class name of the parent table.
23
'refColumns' => 'account_name' //A string or an array of strings naming the primary key column name(s) in the parent table.
24
// there are another two parameters: if not define default are self::CASCADE, execute synchronously
25
// onDelete => self::CASCADE The rule for an action to execute if a row is deleted in the parent table
26
// onUpdate => self::RESTRICT or self::NO_ACTION The rule for an action to not execute if values in primary key columns are updated in the parent table
27
28
),
29
'Engineer' => array(
30
'columns' => 'assigned_to',
31
'refTableClass' => 'Accounts',
32
'refColumns' => 'account_name'
33
),
34
'Verifier' => array(
35
'columns' => array('verified_by'),
36
'refTableClass' => 'Accounts',
37
'refColumns' => array('account_name')
38
)
39
);
40
}
41
42
class BugsProducts extends Zend_Db_Table_Abstract
43
{
44
protected $_name = 'bugs_products';
45
46
protected $_referenceMap = array(
47
'Bug' => array(
48
'columns' => array('bug_id'),
49
'refTableClass' => 'Bugs',
50
'refColumns' => array('bug_id')
51
),
52
'Product' => array(
53
'columns' => array('product_id'),
54
'refTableClass' => 'Products',
55
'refColumns' => array('product_id')
56
)
57
);
58
59
}
2.1 Fetching a Dependent Rowset:

Code
1
$accountsTable = new Accounts();
2
$accountsRowset = $accountsTable->find(1234); // get the rowset by primary key, find( $primary_key_value ) $primary_key_value can be both a single string value and an array
3
$user1234 = $accountsRowset->current(); //convert rowset object to be row object, if not use seek($position) function, it will convert first element
4
5
$bugsReportedByUser = $user1234->findDependentRowset('Bugs'); //findDependentRowset($TableClass, [$rule, [$select]]); $rule is reference rule like 'Reporter'
6
// $select is Zend_Db_Table_Select object like $accountsTable->select()->order('name ASC')->limit(3);
7
// Also we can use magic method:
8
// -- $row->find<TableClass>() $user1234->findBugs();
9
// -- $row->find<TableClass>By<Rule>() $user1234->findBugsByReporter();
10
2.2 Fetching a Parent Row

Code
1 $bugsTable = new Bugs();
2 $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
3 $bug1 = $bugsRowset->current();
4
5 $reporter = $bug1->findParentRow('Accounts'); //findParentRow($table, [$rule]) returns a row object, $rule is optional, default is the the first reference rule like 'Report'
6 //Also it can use function like this: $row->findParent<TableClass>([Zend_Db_Table_Select $select])
7 //$row->findParent<TableClass>By<Rule>([Zend_Db_Table_Select $select])
8
2.3 Fetching a Rowset via a Many-to-many Relationship

Code
1
$bugsTable = new Bugs();
2
$bugsRowset = $bugsTable->find(1234);
3
$bug1234 = $bugsRowset->current();
4
$productsRowset = $bug1234->findManyToManyRowset('Products', 'BugsProducts');
5
//findManyToManyRowset($table, $intersectionTable, [$rule1, [$rule2, [Zend_Db_Table_Select $select] ] ]);
6
// $table: destination table
7
// $intersectionTable : intersection table
8
// The $rule1 : the rule for the relationship from the intersection table to the origin table. In this example, this is the relationship from BugsProducts to Bugs.
9
// The $rule2 : the rule for the relationship from the intersection table to the destination table. In this example, this is the relationship from Bugs to Products.
10
// Also can use magic method:
11
// -- $row->find<TableClass>Via<IntersectionTableClass> ([Zend_Db_Table_Select $select])
12
// -- $row->find<TableClass>Via<IntersectionTableClass>By<Rule1> ([Zend_Db_Table_Select $select])
13
// -- $row->find<TableClass>Via<IntersectionTableClass>By<Rule1>And<Rule2> ([Zend_Db_Table_Select $select])