cvs: peardoc /ja/package/database/db-table intro-database.xml

[email protected] ("TAKAGI Masahiro")
Newsgroups php.pear.doc
Message-ID <cvstakagi1190596816@cvsserver>
takagi		Mon Sep 24 01:20:16 2007 UTC

  Added files:                 
    /peardoc/ja/package/database/db-table	intro-database.xml 
  Log:
  added Japanese translation.
takagi-20070924012016.txt (text/plain, 69.1 KB)
http://cvs.php.net/viewvc.cgi/peardoc/ja/package/database/db-table/intro-database.xml?view=markup&rev=1.1
Index: peardoc/ja/package/database/db-table/intro-database.xml
+++ peardoc/ja/package/database/db-table/intro-database.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- $Revision: 1.1 $ -->

<refentry id="package.database.db-table.intro-database">
 <refnamediv>
   <refname><classname>DB_Table_Database</classname> Class Tutorial</refname>
   <refpurpose>
   Interface to a relational database
   </refpurpose>
 </refnamediv>

<refsect1 id="package.database.db-table.intro-database.desc">
&title.desc;

<para>
<classname>DB_Table_Database</classname> is an database abstraction 
class for a relational database. It is a layer built on top of the 
<classname>DB_Table</classname> class: 
Each table in a <classname>DB_Table_Database</classname> object is 
represented by a <classname>DB_Table</classname> object. 
The most important difference between a 
<classname>DB_Table_Database</classname> object and 
a collection of <classname>DB_Table</classname> objects is that the 
properties of a parent <classname>DB_Table_Database</classname> object 
contain a model of the entire database, including relationships between
tables.
</para><para>
<classname>DB_Table_Database</classname> provides:
<itemizedlist>
<listitem>
  <simpara>
  An object-oriented representation of a relations between tables in a 
  relational database, including linking/association tables that create
  many-to-many relationships.
  </simpara>
</listitem>

<listitem>
  <simpara>
  A simplified API for INSERT, UPDATE, DELETE, and SELECT commands, 
  with an interface very similar to that of the 
  <classname>DB_Table</classname> class.
  </simpara>
</listitem>

<listitem>
  <simpara>
  Automated construction of join conditions for inner joins of any 
  number of tables, based on a list of table names and/or a list of 
  desired column names.
  </simpara>
</listitem>

<listitem>
  <simpara>
  Optional checking of the validity of foreign key values by the PHP 
  layer upon insertion or updating.
  </simpara>
</listitem>

<listitem>
  <simpara>
  Optional PHP emulation of SQL ON DELETE and ON UPDATE referentially 
  triggered actions.
  </simpara>
</listitem>

<listitem>
  <simpara>
  PHP serialization to (and unserialization from) a string that contains 
  the entire database schema.
  </simpara>
</listitem>

<listitem>
  <simpara>
  Serialization to (and unserialization) from XML, using an extension 
  of the MDB2 XML schema. (Unserialization from XML requires PHP 5).
  </simpara>
</listitem>

<listitem>
  <simpara>
  Methods to set various properties of all the child 
  <classname>DB_Table</classname> objects to a common value.
  </simpara>
</listitem>

<listitem>
  <simpara>
  Various utility methods that aid the construction of SQL queries.
  </simpara>
</listitem>

</itemizedlist>
</para>

<para>
Like <classname>DB_Table</classname>, <classname>DB_Table_Database</classname> 
wraps a DB or MDB2 database connection object. The class is compatible with 
both PHP 4 and PHP 5, with the exception of one non-essential method: The 
<link linkend="package.database.db-table.intro-database.xml">
<function>fromXML</function> 
</link> 
method, which creates a <classname>DB_Table_Database</classname> object 
from an XML database schema, requires PHP 5. 
</para>

<para>
Class <classname>DB_Table_Database</classname> extends abstract base class
<classname>DB_Table_Base</classname>. Methods or properties that are inherited
from <classname>DB_Table_Base</classname> are noted as such, and are indicated
in the table of contents of this page with the notation 
"(from <classname>DB_Table_Base</classname>)".
</para>

<para>
This tutorial uses an extended example to introduce the use of the 
<classname>DB_Table_Database</classname> class to create a model of
an interface to a relational database.
</para>

<itemizedlist>
  <title>Contents</title>
  <listitem>
     <simpara><link linkend="package.database.db-table.intro-database.example">Example Database</link></simpara>
  </listitem>
  <listitem>
     <simpara><link
linkend="package.database.db-table.intro-database.constructor">Constructor</link></simpara>
  </listitem>
  <listitem>
     <simpara>
     <link linkend="package.database.db-table.intro-database.model">Building a Model</link>
     </simpara>
     <itemizedlist>
       <listitem>
          <simpara>
          <link linkend="package.database.db-table.intro-database.model.addTable">
          <function>addTable</function></link> - Adding tables
          </simpara>
       </listitem>
       <listitem>
          <simpara><link linkend="package.database.db-table.intro-database.model.addRef">
       <function>addRef</function></link> - Adding references</simpara>
       </listitem>
       <listitem>
          <simpara><link
          linkend="package.database.db-table.intro-database.model.addLink">
          <function>addLink</function></link> - Declaring linking tables</simpara>
       </listitem>
       <listitem>
          <simpara>
            <link linkend="package.database.db-table.intro-database.model.delete">
            Deleting Tables, References, or Links
            </link>
          </simpara>
       </listitem>
     </itemizedlist>
  </listitem>
  <listitem>
     <simpara>
       <link linkend="package.database.db-table.intro-database.refAction">
       Referentially Triggered Actions
       </link>
     </simpara>
     <itemizedlist>
        <listitem>
        <simpara>
          <link linkend="package.database.db-table.intro-database.refAction.addRef">
          Declaring actions with <function>addRef</function>
          </link>
        </simpara>
        </listitem>
        <listitem>
        <simpara>
        <link linkend="package.database.db-table.intro-database.refAction.modifyRefOptions">
          <function>setOnDelete</function> and <function>setOnUpdate</function>
        </link>
        </simpara>
        </listitem>
        <listitem>
          <simpara>
            <link linkend="package.database.db-table.intro-database.refAction.setActOn">
            <function>setActOnDelete</function> and 
            <function>setActOnUpdate</function>
            </link>
          </simpara>
        </listitem>
     </itemizedlist>
  </listitem>
  <listitem>
     <simpara>
        <link linkend="package.database.db-table.intro-database.FKeyCheck">
        Foreign Key Validation</link>
     </simpara>
  </listitem>
  <listitem>
     <simpara>
     <link linkend="package.database.db-table.intro-database.select">
     Data Selection</link>
     </simpara>
     <itemizedlist>
        <listitem>
           <simpara>
           <link linkend="package.database.db-table.intro-database.select.query">
             Query Arrays
           </link>
           </simpara>
        </listitem>
        <listitem>
           <simpara>
           <link linkend="package.database.db-table.intro-database.select.methods">
             <function>select</function>, <function>selectResult</function>, and
             <function>selectCount</function>
           </link> 
           (from <classname>DB_Table_Base</classname>)
           </simpara>
        </listitem>
        <listitem>
           <simpara>
           <link linkend="package.database.db-table.intro-database.select.autoJoin">
           <function>autoJoin</function></link>
           </simpara>
        </listitem>
     </itemizedlist>
  </listitem>
  <listitem>
     <simpara>
     <link linkend="package.database.db-table.intro-database.util">
     SQL Utilities</link>
     </simpara>
     <itemizedlist>
        <listitem>
           <simpara>
              <link linkend="package.database.db-table.intro-database.util.quote">
              <function>quote</function></link>
           </simpara>
        </listitem>
        <listitem>
           <simpara>
              <link linkend="package.database.db-table.intro-database.util.buildFilter">
              <function>buildFilter</function></link>
              (from <classname>DB_Table_Base</classname>)
           </simpara>
        </listitem>
        <listitem>
           <simpara>
              <link linkend="package.database.db-table.intro-database.util.buildSQL">
              <function>buildSQL</function></link>
              (from <classname>DB_Table_Base</classname>)
           </simpara>
        </listitem>
        <listitem>
           <simpara>
              <link linkend="package.database.db-table.intro-database.util.validCol">
              <function>validCol</function></link>
           </simpara>
        </listitem>
     </itemizedlist>
  </listitem>
  <listitem>
     <simpara>
        <link linkend="package.database.db-table.intro-database.modify">
        Data Modification: 
        <function>insert</function>, <function>update</function>, and 
        <function>delete</function></link>
     </simpara>
  </listitem>
  <listitem>
     <simpara>
        <link linkend="package.database.db-table.intro-database.serialize">
        PHP Serialization
        </link>
     </simpara>
     <itemizedlist>
        <listitem>
           <simpara>
              <link linkend="package.database.db-table.intro-database.serialize.setTableSubclassPath">
              <function>setTableSubclassPath</function>
              </link>
           </simpara>
        </listitem>
     </itemizedlist>
  </listitem>
  <listitem>
     <simpara>
        <link linkend="package.database.db-table.intro-database.xml">XML Serialization</link>
     </simpara>
  </listitem>
  <listitem>
     <simpara>
        <link linkend="package.database.db-table.intro-database.DBTableProps">
        Setting <classname>DB_Table</classname> Properties
        </link>
     </simpara>
  </listitem>
  <listitem>
     <simpara>
     <link linkend="package.database.db-table.intro-database.get">Get* Methods</link>
     </simpara>
  </listitem>
</itemizedlist>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.example">
<title>Example Database</title>
<para>
Throughout this tutorial, our examples will refer to a 
<classname>DB_Table_Database</classname> 
object for an example database named TestDB, which is described below. 
The child <classname>DB_Table</classname> objects that are associated 
with RDBMS tables must all be instantiated first, and then added to 
(i.e., linked with) a parent <classname>DB_Table_Database</classname> 
object. 
</para>
<para>
The example database TestDB stores names, numbers, and addresses 
for a set of people, and contains 4 tables. Peoples names, phone 
numbers, and addresses are stored in three tables named Person, 
Phone, and Address, respectively.  To allow for the fact that 
several people may share a phone number, and that a person may 
have more than one phone number, the database allows the creation 
of a many-to-many relationship between Person and Phone. This
relationships are established by an additional linking table, named 
PersonPhone, which contains foreign key references to Person and 
Phone.
</para> 

<para>
DB_Table objects must be instantiated before they can be added to 
a parent <classname>DB_Table_Database</classname> instance. The usual 
way of creating a <classname>DB_Table</classname> object (as discussed 
in the tutorial for that class) is to create one subclass of 
<classname>DB_Table</classname> for each table, and create one instance 
of each such subclass. In this tutorial, we use a convention in which 
the subclass of <classname>DB_Table</classname> associated with a 
database table named "Entity" is Entity_Table, and in which the single 
object of this class is $Entity. This is also the convention used in
code generated by the <classname>DB_Table_Generator</classname> class.
</para> <para>
The following code defines a subclass <classname>Person_Table</classname> 
that represents a database table Person:
<programlisting role="php">
<![CDATA[
<?php
require_once 'DB/Table.php'

class Person_Table extends DB_Table
{
    // Define columns
    $col = array (
        'PersonID' => array('type' => 'integer', 'require' => true),
        'FirstName' => array('type' => 'char', 'size' => 32, 'require' => true),
        'MiddleName' => array('type' => 'char', 'size' => 32),
        'LastName' => array('type' => 'char', 'size' => 64, 'require' => true),
        'NameSuffix' => array('type' => 'char', 'size' => 16),
        'AddressID' => array('type' => 'integer')
    );

    // Define indices. PersonID is declared to be the primary index
    $idx = array(
        'PersonID' => array('cols' => 'PersonID',  'type' => 'primary'),
        'AddressID' => array('cols' => 'AddressID', 'type' => 'normal')
    );

    // Declare 'PersonID' to be an auto-increment column
    $auto_inc_col = 'PersonID';

}
?>]]>
</programlisting>
Here, 'PersonID' is the primary index of the Person table. Column 
AddressID is a foreign key that references the primary key of the 
Address table (defined below). 
</para><para>
Note the assignment of a value for the $auto_inc_col property, which 
is a recent addition to <classname>DB_Table</classname>: The value of 
$auto_inc_col is the name of a column that is declared to be 'auto increment'. 
Auto incrementing of this column is now implemented in the insert method 
of <classname>DB_Table</classname> using DB or MDB2 sequences.
</para><para>
The following code uses the same method to create subclasses of 
<classname>DB_Table</classname> associated with the remaining Phone, 
Address, and PersonPhone tables of database TestDB:
<programlisting role="php">
<![CDATA[<?php
class Address_Table extends DB_Table
{
    $col = array(
        'AddressID' => array('type' => 'integer', 'require' => true),
        'Building' => array('type' => 'char', 'size' =>16),
        'Street' => array('type' => 'char', 'size' => 64),
        'UnitType' => array('type' => 'char', 'size' => 16),
        'Unit' => array('type' => 'char', 'size' => 16),
        'City' => array('type' => 'char', 'size' => 64),
        'StateAbb' => array('type' => 'char', 'size' => 2),
        'ZipCode' => array('type' => 'char', 'size' => 16)
    );
    $idx = array(
        'AddressID' => array('cols' => 'AddressID', 'type' => 'primary'),
    );
    $auto_inc_col = 'AddressID';
}
?>]]>
</programlisting>
<programlisting role="php">
<![CDATA[<?php
class Phone_Table extends DB_Table
{
    $col = array(
        'PhoneID' => array('type' => 'integer', 'require' => true),
        'PhoneNumber' => array('type' => 'char', 'size' => 16, 'require' => true),
        'PhoneType'   => array('type' => 'char', 'size' => 4)
    );
    $idx = array(
        'PhoneID' => array('cols' => 'PhoneID', 'type' => 'primary')
    );
    $auto_inc_col = 'PhoneID';
}
?>]]>
</programlisting>
<programlisting role="php">
<![CDATA[<?php
class PersonPhone_Table extends DB_Table
{
    $col = array(
        'PersonID' => array('type' => 'integer', 'require' => true),
        'PhoneID'  => array('type' => 'integer', 'require' => true)
    );

    $idx = array(
        'PersonID' => array('cols' => 'PersonID', 'type' => 'normal'),
        'PhoneID' => array('cols' => 'PhoneID', 'type' => 'normal')
    );
}
?>
]]>
</programlisting>
In ths example, the PhoneType column of table Phone is used to distinguish 
home, work, and cell phones, and so must have one of the 4 character values 
'HOME', 'WORK' or 'CELL'.
</para><para>
The following code instantiates one object of each <classname>DB_Table</classname> 
subclass, which is associated with the corresponding table:
<programlisting role="php">
<![CDATA[<?php
$Person = new Person_Table($conn, 'Person', 'safe');
$Address = new Address_Table($conn, 'Address', 'safe');
$Phone = new Phone_Table($conn, 'Phone', 'safe');
$PersonPhone = new PersonPhone_Table($conn, 'PersonPhone', 'safe');
?>]]>
</programlisting>
Here, because we have used the value 'safe' for the optional third 
parameter of the <classname>DB_Table</classname> constructor in each 
statement, each table will be created in the RDBMS only if and only 
if a table of that name does not already exist in the database.
</para>

<para>
It is recommended that constructor statements be placed in a separate 
file from any of the <classname>DB_Table</classname> subclass definitions. 
Doing so makes it easier to 
<link linkend="package.database.db-table.intro-database.serialize">
serialize and unserialize</link> the 
<classname>DB_Table</classname> and <classname>DB_Table_Database</classname> 
objects, because a php file in which an instance of a 
<classname>DB_Table</classname> subclass is unserialized must have access 
to the subclass definition, but should not include the constructor statements. 
Putting each <classname>DB_Table</classname> subclass definition in a separate 
file, with a name that is the subclass name with a .php extension, also allows 
the subclass definitions to be autoloaded when an object is serialized, as 
discussed 
<link linkend="package.database.db-table.intro-database.serialize">below</link>.
</para>

<para>
An alternative way to create a <classname>DB_Table</classname> object is to 
create an instance of <classname>DB_Table</classname> itself, rather than 
of a subclass of <classname>DB_Table</classname>.  In this method, one first 
instantiates a generic <classname>DB_Table</classname> object, which initially 
contains no information about the table schema, and then sets the values of 
the public $col and $idx properties needed to define a table schema. As an 
example, the following code constructs an instance of DB_Table that represents 
the Person table:
<programlisting role="php">
<![CDATA[<?php
$Person = new DB_Table($conn, 'Person');

$Person->col['PersonID'] = array('type' => 'integer', 'require' => true);
$Person->col['FirstName'] = array('type' => 'char', 'size' => 32, 'require' => true);
$Person->col['MiddleName'] = array('type' => 'char', 'size' => 32);
$Person->col['LastName'] = array('type' => 'char', 'size' => 64, 'require' => true);
$Person->col['NameSuffix'] = array('type' => 'char', 'size' => 16);
$Person->col['AddressID'] = array('type' => 'integer');

$Person->idx['PersonID'] = array('cols' => 'PersonID', 'type' => 'primary');
$Person->idx['PersonID'] = array('cols' => 'PersonID', 'type' => 'normal');

$Person->auto_inc_col = 'PersonID';
?>
]]>
</programlisting>
This method is valid only in recent versions of the 
<classname>DB_Table</classname> package (1.5.0RC1 and greater) that contain 
the <classname>DB_Table_Database</classname> class. Earlier versions of 
<classname>DB_Table</classname> required that <classname>DB_Table</classname> 
always be extended.  The only real disadvantage of using such generic 
<classname>DB_Table</classname> objects is that it makes it impossible to 
override the methods of <classname>DB_Table</classname> to, for example, 
customize the insert or update method so as to implement business rules 
for a table. Generic <classname>DB_Table</classname> objects are used by 
the <function>fromXML</function> method, which takes an XML description of 
a database schema as a parameter, and returns a 
<classname>DB_Table_Database</classname> object in which each of the child 
tables is represented by an instance of <classname>DB_Table</classname>. 
</para>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.constructor">
<title>Constructor</title>
<para>
A <classname>DB_Table_Database</classname> object is instantiated as an 
empty shell, to which tables, foreign key references, and links are then 
added. The constructor interface is
<programlisting>
<![CDATA[

void DB_Table_Database(DB/MDB2 object $conn, string $name)

]]>
</programlisting>
The parameter $conn must be either a DB or MDB2 object, which establishes
a connection to a RDBMS.  The $name parameter is the name of the 
database. To instantiate an object that represents a database named 
TestDB with a DB connection to a MySQL database, we might thus use 
(with no error checking):
<programlisting role="php">
<![CDATA[<?php
require_once 'DB/Table/Database.php'

$conn = DB::connect("mysqli://$user:$password@$host");
$db = new DB_Table_Database($conn, 'TestDB');
?>]]>
</programlisting>
where the values of $user, $password, and $host are the user name,
database password, and host machine, respectively.
</para>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.model">
<title>Building a Model</title>
<para>
To construct a model of a relational database, after instantiating a 
set of <classname>DB_Table</classname> objects and a 
<classname>DB_Table_Database</classname> object, we must add the table 
objects to the database object, add declarations of foreign key 
references, and declare many-to-many relationships that involve linking 
tables, in that order.
</para>

<refsect2 id="package.database.db-table.intro-database.model.addTable">
<title>Adding Tables</title>
<para>
After a <classname>DB_Table</classname> object is instantiated, it 
can be added to the parent database with the 
<function>DB_Table_Database::addTable</function> method. The interface 
for this method is
<programlisting>
<![CDATA[

true|PEAR_Error addTable(object &$Table)

]]>
</programlisting>
where $Table is a <classname>DB_Table</classname> object that is passed 
by reference. The method returns boolean true on normal completion, and 
a <classname>PEAR_Error</classname> object on failure.
</para><para>
The following code adds the four tables of our example database to 
the $db <classname>DB_Table_Database</classname> object:
<programlisting role="php">
<![CDATA[
<?php
$db->addTable($Person);
$db->addTable($Address);
$db->addTable($Phone);
$db->addTable($PersonPhone);
?>
]]>
</programlisting>
In this and all subseqent examples, we omit the error handling code
that should be added to production code. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.model.addRef">
<title>Adding Foreign Key References</title>
<para>
After tables have been added to a database, we can use the 
<function>addRef</function> method to add references between pairs 
of tables. 
</para><para>
Synopsis (simplified):
<programlisting>
<![CDATA[

true|PEAR_Error addRef(string $ftable, string|array $fkey, 
                       string $rtable, [string|array $rkey] )

]]>
</programlisting>
Here $ftable is the name of a referencing (or foreign key) table, $fkey 
is the foreign key, $rtable is the name of the referenced table, and $rkey 
is the (optional) referenced key. If the optional $rkey parameter is absent 
or null, the referenced key is taken by default to be the primary key of 
the referenced table.  The foreign and referenced key values are specified 
using the same syntax as that used to define indices in 
<classname>DB_Table</classname>: Each key 
may be either a column name string, for a single-column key, or a sequential 
array of column names, for a multi-column key. The method returns true on 
normal completion, and a <classname>PEAR_Error</classname> on failure.  The 
simplified synopsis shown here does not include two more optional parameters 
(parameters 5 and 6) that can be used to specify 'on delete' and 'on update' 
actions. The full interface is presented 
<link linkend="package.database.db-table.intro-database.refAction.addRef">
below</link>.

For example, the command:
<programlisting role="php">
<![CDATA[
<?php
$db->addRef('Person', 'AddressID', 'Address', 'AddressID');
?>
]]>
</programlisting>
adds a reference from foreign key Person.AddressID of referencing table 
Person to the primary key Address.AddressID of referenced table Address. 
Because the referenced key 'AddressID' is also the primary key of table
'Address' this could also be written as:
<programlisting role="php">
<![CDATA[<?php
$db->addRef('Person', 'AddressID', 'Address');
?>]]>
</programlisting>
When the referenced key is explicitly specified, as in the first example, 
it should always be either a primary key or a key for which a unique index 
is defined, as required by standard SQL.
</para><para>
A reference between two tables can only be added after both the referencing 
and referenced <classname>DB_Table</classname> objects have been instantiated 
and added to the parent <classname>DB_Table_Datbase</classname> instance. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.model.addLink">
<title>Adding Links</title>
<para>
A table may be declared to be a "linking" table that establishes a 
many-to-may relationship between two others. The only effect of such 
a declaration is to change the action of the autoJoin method: 
If a table named $link is declared to be a linking table that creates 
a many-to-many relationship between tables named $table1 and $table2, 
then the autoJoin method may use the linking table to join $table1 
and $table2, if necessary. 
</para><para>
Method <function>addLink</function> declares a table to be a 
linking or association table for two others.
</para><para>
Synopsis:
<programlisting>
<![CDATA[

true|PEAR_Error addLink(string $table1, string $table2, string $link)

]]>
</programlisting>
Here, $link is the name of a linking table that links tables named 
$table1 and $table2. All three parameters are required, and all must 
be valid table name strings.  It does not matter which of the two 
linked tables, $table1 and $table2, is listed first and which second 
in the function call. A table that links $table1 and $table2 must have 
foreign keys that references to both of the linked tables.  A link can 
only be added to the model after the references from the linking table 
to both of the linked tables have been added.  The method returns true
on normal completion and a <function>PEAR_Error</function> if an error 
is detected. 
</para>
<para>
For example, the command:
<programlisting role="php">
<![CDATA[
<?php
$db->addLink('Person', 'Phone, 'PersonPhone')
?>
]]>
</programlisting>
declares PersonPhone to be a linking table that links tables Person
and Phone.
</para><para>
The <function>addLink</function> method will not prevent one from 
declarating more than one linking table for the same two linked 
tables. Doing so would make the link declaration useless, however, 
because the <function>autoJoin</function> method will fail if it 
needs to use a linking table to join a pair of tables, but finds 
that more than one of linking table is declared for those two 
tables. 
</para><para>
The command
<programlisting role="php">
<![CDATA[<?php
$db->addAllLinks()
?>
]]>
</programlisting>
adds all possible linking tables to the database. In this method,
any table that has foreign keys that reference tables $table1 and
$table2 is declared to be a link between $table1 and $table2. In
some databases, the easiest way to declare links may be by using
the addAllLinks method to create all possible links and then using
the 
<link linkend="package.database.db-table.intro-database.model.delete">
<function>deleteLink</function></link> method to delete those that 
are not desired. 
</para>
<para>
The database model is complete when all of the tables have been
added, all of the references have been added, and all the links 
have been added. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.model.example">
<title>Example - Putting it Together</title>
<para>
For our example, let us create a directory in which to put all of 
the code required as an interface to a database. We will put each 
<classname>DB_Table</classname> subclass definition in a separate 
file in this directory, in which each file name is simply the class
name with a '.php' extension. In addition, it is convenient to create 
a single file, which we will call 'Database.php', in which we create
a DB or MDB2 connection, create one object per table, and construct
a parent <classname>DB_Table_Database</classname> object. This file 
structure is used by the <classname>DB_Table_Generator</classname> 
class for code that is auto-generated for an existing database. 
Below is a listing of the minimal 'Database.php' file required for
our example database:
</para>

<example>
<title>Database.php File</title>
<programlisting role="php">
<![CDATA[
<?php
require_once 'MDB2.php';
require_once 'DB/Table/Database.php';
require_once 'Person_Table.php';
require_once 'Address_Table.php';
require_once 'Phone_Table.php';
require_once 'PersonPhoneAssoc_Table.php';

// NOTE: User must uncomment & edit code to create $dsn
$phptype  = 'mysqli';
$username = 'root';
$password = 'password';
$hostname = 'localhost';
$dsn = "$phptype://$username:$password@$hostname";

// Instantiate DB/MDB2 connection object $conn
$conn =& MDB2::connect($dsn);
if (PEAR::isError($conn)) {
    print "Error connecting to database server\n";
    print $conn->getMessage();
    die;
}

// Create one instance of each DB_Table subclass
$Person = new Person_Table($conn, 'Person');
$Address = new Address_Table($conn, 'Address');
$Phone = new Phone_Table($conn, 'Phone');
$PersonPhoneAssoc = new PersonPhoneAssoc_Table($conn, 'PersonPhoneAssoc');

// Instantiate a parent DB_Table_Database object $db
$db = new DB_Table_Database($conn, '42A');

// Add DB_Table objects to parent DB_Table_Database object
$db->addTable($Person);
$db->addTable($Address);
$db->addTable($Phone);
$db->addTable($PersonPhoneAssoc);

// Add foreign references
$db->addRef('PersonPhoneAssoc', 'PersonID', 'Person');
$db->addRef('PersonPhoneAssoc', 'PhoneID', 'Phone');
$db->addRef('Person', 'AddressID', 'Address');

// Add all possible linking tables 
$db->addAllLinks();

?>
]]>
</programlisting>
</example>

<para>
This example file is very similar to the skeleton file that would 
be created by <classname>DB_Table_Generator</classname> for an 
existing database with this structure. The main differences are
that some lines in the auto-generated file would have to be 
uncommented or edited to produce the above (<emphasis>e.g.</emphasis>,
the lines that define the database DSN). In this example, the call
to <function>addAllLinks</function> method would correctly identify 
'PersonPhoneAssoc' as a table that links 'Person' and 'Phone'. This
example does not include any referentially triggered 'ON DELETE' or 
'ON UPDATE' actions, discussed below, which could be added to the
end of the same file.
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.model.delete">
<title>Deleting Tables, References, and Links</title>
<para>
The 
<function>deleteTable</function>, 
<function>deleteRef</function>, and 
<function>deleteLinks</function>
methods can be used to delete 
tables, and foreign key references, and linking table declarations, 
respectively, from the <classname>DB_Table_Database</classname> model.
</para>

<para id="package.database.db-table.intro-database.model.delete.table">
<function>deleteTable</function> - deletes a table from the database model
</para>

<para>
Synopsis:
<programlisting>
<![CDATA[

void deleteTable(string $table)

]]>
</programlisting>
Parameter $table is the name of the table to be deleted. Deletion 
of a table causes deletion of the table and all other entities of 
the model that depend on the existence of that table, including
foreign key references to or from that table, and linking
relationships that depend upon the existence of those foreign
key references.
</para>

<para id="package.database.db-table.intro-database.model.delete.ref">
<function>deleteRef</function> - deletes a reference from the database model
</para>
<para>
Synopsis:
<programlisting>
<![CDATA[

void deleteRef(string $ftable, string $rtable)

]]>
</programlisting>
where $ftable and $rtable are the names of the referencing and 
referenced tables, respectively. Deletion of a foreign key reference 
causes deletion of any links that rely on the existence of that 
reference, i.e., links in which $ftable is the linking table and 
$rtable is one of the linked tables.
</para>
<para id="package.database.db-table.intro-database.model.delete.Link">
<function>deleteLink</function> - deletes a linking table declaration 
</para>
<para>
Synopsis:
<programlisting>
<![CDATA[

void deleteLink(string $table1, string $table2, [string $link])

]]>
</programlisting>
Here $table1 and $table2 are names of the linked tables, and the
optional parameter $link is the name of the linking table. If $link 
is null or absent, all declarations of linking tables between $table1 
and $table2 are deleted. If $link is present, only the declaration of 
$link as a linking table between $table1 and $table2 is deleted (if 
one exists). The <function>deleteLinks</function> method may be used 
after the <function>addAllLinks</function> to prune the resulting set 
of linking table declarations.
</para>
</refsect2>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.refAction">
<title>On Delete and On Update Actions</title>
<para>
<classname>DB_Table_Database</classname> optionally provides actions designed 
to enforce referential integrity that are provided by ANSI SQL, but that are 
not provided by some popular databases (e.g., SQLite and the default 
MySQL engine).  <classname>DB_Table_Database</classname> offers optional PHP 
emulation of referentially triggered ON DELETE and ON UPDATE actions, such 
as cascading deletes (discussed here), and also optionally checks the 
validity of foreign key values before insertion or updating 
(discussed 
<link linkend="package.database.db-table.intro-database.FKeyCheck">below</link>)
</para>
<para>
The ON DELETE and ON UPDATE actions associated with a reference 
(if any) may be declared either as additional parameters to 
<link linkend="package.database.db-table.intro-database.refAction.addRef">
<function>addRef</function></link>, or by using 
<link
linkend="package.database.db-table.intro-database.refAction.modifyRefOptions">
<function>setOnDelete</function> and <function>setOnUpdate</function></link>.
</para>

<refsect2 id="package.database.db-table.intro-database.refAction.addRef">
<title>Declaring actions in <function>addRef</function></title>
<para>
Actions to be taken on deletion or updating of a referenced row may
may be declared when a reference is added to the model using two 
optional parameters of the <function>addRef</function> method. The following 
example shows the extended form of <function>addRef</function> needed to add 
a reference from PersonPhone to Person (as above), while also declaring a 
cascade action on delete of a referenced row of Person, and a restrict 
action on update of such a row:
<programlisting role="php">
<![CDATA[<?php
$db->addRef('PersonPhone', 'PersonID', 'Person', null, 'cascade', 'restrict');
?>]]>
</programlisting>
Here, a null value of the fourth parameter is used to indicate that 
the referenced key should be taken, by default, to be primary key of 
referenced table Person.  The values of the fifth and sixth parameters 
represent actions to be taken upon delete ('cascade') and upon update 
('restrict'), respectively.  A null or absent value for either of 
these parameters indicates that no referentially triggered action 
should be taken on delete or on update.
</para>
<para>
The effect of the 'cascade' values of the fifth parameter in the above 
example is to declare that that all referencing rows of PersonPhone should 
be deleted upon deletion of a corresponding referenced row of Person (a 
cascading delete). The 'restrict' value of the sixth parameter declares 
that updating of the primary key PersonID of Person should be prevented 
(the 'restrict' on update action), and an error should be thrown by the
update method, in rows of Person that are referenced by rows of 
PersonPhone.
</para>

<para>
The full interface of the <function>addRef</function> method is:
<programlisting>
<![CDATA[

true|PEAR_Error addRef(string $ftable, mixed $fkey, string $rtable, [mixed $rkey], 
                       [string|null $on_delete], [string|null $on_update])

]]>
</programlisting>
Here, $ftable is the referencing table, $fkey is the foreign key, $rtable 
is referenced table, and $rkey is the referenced key.  The $fkey and $rkey 
parameters may be column name strings or arrays of column names, or $rkey 
may be null.  An absent or null value of $rkey indicates a reference to 
the primary key of the referenced table.  The $on_delete and $on_update 
parameters indicate actions to be taken on deletion or updating of a 
referenced row.  The only allowed values of $on_delete and $on_update are 
the string literals
<programlisting>
'cascade' | 'restrict' | 'set null' | 'set default' 
</programlisting> 
or PHP null, which is the default value for both parameters. Each of 
the allowed action strings is the lower case form of a standard SQL 
action, and turns on PHP emulation of the corresponding action. An 
absent or null value for either action indicates that no action should 
be taken at the PHP layer upon delete or update of a referenced row.
(Note that a PHP null value is different from the 'set null' action 
string.)
</para>
<para>
The following example declares all of the foreign key references needed 
in our example database, with appropriate referentially triggered actions:
<programlisting role="php">
<![CDATA[<?php
$db->addRef('Person', 'AddressID', 'Address', null, 'set null', 'cascade');
$db->addRef('PersonPhone', 'PersonID', 'Person', null, 'cascade', 'cascade');
$db->addRef('PersonPhone', 'PhoneID', 'Phone', null, 'cascade', 'cascade');
?>]]>
</programlisting>
As a result of these declarations, rows in the linking table PersonPhone will 
be deleted when corresponding rows of either Person or Phone are deleted, and 
updated if the primary keys of reference rows Person or Phone are modified. 
The foreign key AddressID of a row in table Person will be set to null if the 
corresponding referenced row of Address is deleted (to indicate that no 
address is known), and updated if the primary key of that row in Address is 
modified. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.refAction.modifyRefOptions">
<title>
  <function>setOnDelete</function> and <function>setOnUpdate</function>
</title>
<para>
The referentially triggered actions associated with a foreign key 
reference may also be changed, or turned off, with the 
<function>setOnDelete</function> and <function>setOnUpdate</function> 
methods.
</para><para>
Synopses:
<programlisting>
<![CDATA[

void setOnDelete(string $ftable, string $rtable, string|null $action)
void setOnUpdate(string $ftable, string $rtable, string|null $action)

]]>
</programlisting>
Here, $ftable and $rtable are the names of referencing (foreign key) 
and referenced table, respectively, for an existing reference. The 
$action parameter is the value for the on_delete or on_update action 
for that reference, i.e., either an action strings or null. A null 
parameter is used to indicate that no action on delete or update of 
rows of table $rtable. 
</para>
<para>
For example, the following code would change the 'on_update' action 
associated with the the reference from 'PersonPhone' to 'Person' to 
a 'restrict' action:
<programlisting role="php">
<![CDATA[<?php
$db->setOnUpdate('PersonPhone', 'Person', 'restrict');
?>]]>
</programlisting>
The effect this is to prohibit updates of the primary key value in 
rows of Person that are referenced by rows of PersonPhone.
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.refAction.setActOn">
<title>
<function>setActOnDelete</function> and <function>setActOnUpdate</function>
</title>
<para>
PHP emulation of referentially triggered actions may be turned on or 
off for the entire database by the 
<function>setActOnDelete</function> and 
<function>setActOnUpdate</function> methods.
</para>
<para>
Synopses:
<programlisting>
<![CDATA[

void setActOnDelete(bool $flag)
void setActOnUpdate(bool $flag)

]]>
</programlisting>
Passing a true value to either method activates PHP emulation of all 
of the declared ON DELETE or ON UPDATE actions, respectively, while a 
false value turns off PHP emulation of the corresponding action. By 
default, PHP emulation of both ON DELETE and ON UPDATE actions is on.
Calling either of these methods with a false value does not modify
the values of the instance property (the $_ref property) that records 
the on delete or on update actions associated with each reference: 
It merely prevents PHP emulation of these actions by the 
<function>DB_Table_Database::delete</function> and 
<function>DB_Table_Database::update</function> methods.
</para>
</refsect2>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.FKeyCheck">
<title>Foreign Key Validation</title>
<para>
By default, <classname>DB_Table_Database</classname> checks the validity 
of foreign key values before inserting or updating data in a table with 
foreign keys. That is, before inserting a row, or updating any foreign key 
column values, the <function>insert</function> and <function>update</function>
methods of <classname>DB_Table_Database</classname> actually submit a query 
to confirm that the inserted or updated foreign key column values correspond 
to values of the referenced columns of an existing row in the referenced 
table. By default, both methods throw an error, and do not modify the data, 
if this check fails. 
</para>
<para id="package.database.db-table.intro-database.FKeyCheck.setCheckFKey">
This checking of foreign key validity by the PHP layer may be turned on 
or off, for insertion or updating of any table in database, with the 
<function>setCheckFKey</function> method. The interface of this method is:
<programlisting>
<![CDATA[

void setCheckFKey(bool $flag)

]]>
</programlisting>
Passing a true value of $flag turns on checking of foreign keys (the
default), while a false value turns checking off. 
</para>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.select">
<title>Data Selection</title>
<para>
<classname>DB_Table_Database</classname> provides an object-oriented 
interface for SQL select statements that is almost identical to that of 
<classname>DB_Table</classname>.
</para>

<refsect2 id="package.database.db-table.intro-database.select.query">
<title>Query Arrays</title>
<para>
As in <classname>DB_Table</classname>, queries are represented in 
<classname>DB_Table_Database</classname> as arrays, in which array 
elements represents clauses of a corresponding SQL select statement. 
For example, a query for names of all people that live on Oak Street 
in Anytown in our example database might be 
<programlisting>
<![CDATA[
<?php
$oak = array(
   'select'  => 'Person.FirstName, Person.LastName, Address.Building',
   'from'    => 'Person, Address',
   'where'   => "Person.AddressID = Address.AddressID\n" 
              . "  AND Address.Street = 'Oak Street'\n"
              . "  AND Address.City = 'AnyTown'",
   'order'   => 'Address.Building' );
?>]]>
</programlisting>
The 
<link linkend="package.database.db-table.intro-database.util.buildSQL">
<function>buildSQL</function></link> method accepts such a query array as 
a parameter and returns the corresponding SQL command string. For example
<programlisting role="php">
<![CDATA[
<?php
echo $db->buildSQL($oak);
?>]]>
</programlisting>
yields the output
<programlisting>
SELECT Person.FirstName, Person.LastName, Address.Building
FROM Person, Address
WHERE Person.AddressID = Address.AddressID
  AND Address.Street = 'Oak Street'
  AND Address.City = 'AnyTown'
ORDER BY Address.Building
</programlisting>
The string values of most values in this array are passed to the 
RDBMS unmodified, prefixed by the keywords 'SELECT', 'FROM', etc. 
Column names that appear in only one table often do not need to be 
qualified by table names, as they are in the above example.
</para><para>
As in <classname>DB_Table</classname>, such query arrays can be stored 
in the public $sql property array:
<programlisting role="php">
<![CDATA[
<?php
$db->sql['oak'] = $oak
?>]]>
</programlisting>
Representing queries as arrays, rather than strings, makes it easier 
for baseline queries to be modified by, for example, adding additional 
limitations to the end of the 'where' clause string.
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.select.methods">
<title>Select* Methods: 
  <function>select</function>, <function>selectResult</function>, and
  <function>selectCount</function>
</title>
<para>
The <function>select*</function> methods are inherited by both the 
<classname>DB_Table_Database</classname>  and <classname>DB_Table</classname>
classes from the <classname>DB_Table_Base</classname> class, and thus 
share the same interface and behavior. The interface is also the same
for all three methods. The required first parameter can be either the 
key for a previously stored query array, as in
<programlisting role="php">
<![CDATA[<?php
$result = $db->select('oak')
?>]]>
</programlisting>
or the corresponding array value as a parameter, as in
<programlisting role="php">
<![CDATA[<?php
$result = $db->select($oak)
?>]]>
</programlisting>
The select method returns a result set as a numerically indexed array of 
rows. Each row can represented as be either an associative or numerical 
array, or an object, depending on the value of the $fetch_mode property of 
the <classname>DB_Table_Database</classname> object or (if this is null) 
the fetchmode of the underlying DB or MDB2 object. 
</para> 

<para>
The common interface of three select* methods
<function>select</function>, 
<function>selectCount</function>, and 
<function>selectResult</function> is:
<programlisting>
<![CDATA[

mixed select*( array|string $sql_key, [string $filter], [string $order], 
               [int $start], [int $count], [array $params])

]]>
</programlisting>
As discussed above, $sql_key is either a query array, or the key of 
a baseline query array that has been stored in the $sql property. The 
$filter parameter is an SQL logical expression string that limits the 
result set. This condition is added (i.e., ANDed) to the end of the 
'where' element of the $sql_key query array. The $order parameter is 
an ORDER BY clause (without the ORDER BY prefix) that can be used to 
override any 'order' element of the $sql_key array.  Integer parameters 
$start is which the position within the full result set of the first 
row that should be included in the return value, while $count is the 
maximum number of rows desired within the return value. If present, 
$params is an array in which the values are parameters for placeholder 
substitution in a prepared query. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.select.autoJoin">
<title><function>autoJoin</function></title>
<para>
<function>autoJoin</function> - accepts an array paramater containing 
the names of desired columns and/or an array of tables names, and returns 
a query array containing a WHERE clause with automatically 
generated join conditions.
</para>
<para>
Synopsis:
<programlisting role="php">
<![CDATA[

array|PEAR_Error autoJoin([array $cols], [array $tables], [string $filter])

]]>
</programlisting>
Here, $cols is a sequential array of the names of the desired columns, 
$tables is a sequential array of names of tables to be joined, and
$filter is an SQL logical statement that may be used to limit the
results. The $filter clause is added (i.e., ANDed) to the end of the
the 'where' element, after the automatically generated join 
conditions.  Both the $col and $tables parameter are optional, but 
at least one of them must be supplied. The query returned by 
autoJoin is an inner join of a set of tables containing all of those 
listed in the $tables parameter, all of the tables containing the 
columns listed in the $cols parameter, and any linking tables 
required to join these tables. 
</para>
<para>
The following example generates and submits query that selects a result 
set in which each row contains a person's name, home phone number and 
address, based on knowledge of the names of the desired columns. In our 
example database, this requires that all four tables be joined. 
<programlisting role="php">
<![CDATA[
<?php
$cols = array('FirstName', 'LastName', 'PhoneNumber', 'Building', 'Street', 'City')
$report = $db->autoJoin($cols, "Phone.PhoneType = 'HOME'");
$result = $db->select($report);
?>
]]>
</programlisting>
Note that the column names in the $cols parameter do not need to be 
qualified by table names if they are unambiguous -- the autoJoin 
method internally uses the 
<link linkend="package.database.db-table.intro-database.util.validCol">
<function>validCol</function></link> 
method to validate and disambiguate all qualified and unqualified 
column names.
</para>
<para>
The SQL command corresponding to such a query array may be obtained
using 
<link linkend="package.database.db-table.intro-database.util.buildSQL">
<function>buildSQL</function></link>. In this example,the command
<programlisting role="php">
<![CDATA[
<?php
echo $db->buildSQL($report);
?>
]]>
</programlisting>
yields
<programlisting>
SELECT Person.FirstName, Person.LastName, Phone.PhoneNumber, Address.Building, Address.Street, Address.City
FROM Person, Phone, Address, PersonPhone
WHERE PersonPhone.PhoneID = Phone.PhoneID
  AND PersonPhone.PersonID = Person.PersonID
  AND Person.AddressID = Address.AddressID
</programlisting>
If <function>autoJoin</function> is passed only a set of column names, 
as in the above example, it identifies the set of tables that contain 
those columns, and joins those tables, plus any linking tables needed 
to create many-to-many relationships.
</para><para>
In the following example, the $cols parameter is null, but the names 
of the tables to be joined are specified in the $tables parameter:
<programlisting role="php">
<![CDATA[
<?php
$tables = array('Person', 'Address', 'Phone');
$report = $db->autoJoin(null,$tables);
$result = $db->select($report);
?>
]]>
</programlisting>
The corresponding SQL command is
<programlisting>
SELECT *
FROM Person, Phone, Address, PersonPhone
WHERE PersonPhone.PhoneID = Phone.PhoneID
  AND PersonPhone.PersonID = Person.PersonID
  AND Person.AddressID = Address.AddressID
</programlisting>
When the first argument of autoJoin is null, as in this example,
the SELECT clause is taken to be 'SELECT * by default. Note that
the FROM and WHERE clauses join a linking table PersonPhone that 
was not explicitly specified, because this table was necessary 
to join two of the tables containing the desired data. 
</para>

<para>
Algorithm: 
The algorithm used by <function>autoJoin</function> is designed to 
find appropriate join conditions if these exist and are unambiguous, 
and to return a PEAR Error if the structure of references and linking 
tables either yields a multiply connected network of joins, or if it 
cannot construct an appropriate set of join conditions.  The method 
first examines the $col and $table property to identify the list of 
tables that must be joined. It then creates a network of joined tables 
(the joined set) by starting with one table and sequentially adding 
tables to the joined set from the set of tables have not yet been 
joined (the unjoined set). The process starts by taking the first 
required table as a nucleus of the joined set, and then iterating 
through the unjoined set in search of a table that can be joined to 
the first.  During this and each subsequent stage of addition, the 
method iterates through the unjoined set in search of a table that 
can be joined to any table in the joined set (i.e., that either 
references or is referenced by one of the tables in the joined set.)  
If it finds an unjoined table that can be joined to exactly one table 
in the joined set, that table is added to the joined set, and the 
search for another table to join begins.  If the search encounters 
a table in the unjoined set that can be joined to two or more tables 
in the joined set, the method returns an error indicating that the 
join conditions are ambiguous -- the method will only return a set 
of joins that correspond to a tree graph (where tables are nodes and 
joins are bonds) and will reject any multiply connected set of 
joins. If it is found that none of the tables in the unjoined 
set can be directly joined to any table in the joined set, the 
method then cycles through the unjoined set again in search of 
a table that can be joined to exactly one table in the joined 
set through a linking tables.  If it finds a table that is 
connected via linking tables to two or more tables in the 
joined set, it will also return an error. If the search does 
not identify any unjoined table that can be joined to a table 
in the joined set either through a direct reference or a linking 
table, the method returns an error indicating that the required 
set of tables can not be joined. 
</para>
</refsect2>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.util">
<title>SQL Utilities</title>

<refsect2 id="package.database.db-table.intro-database.util.quote">
<title><function>quote</function></title>
<para>
The quote method returns an SQL literal string representation of the 
parameter $value.
</para><para>
Synposis:
<programlisting>
<![CDATA[

string quote(mixed $value)

]]>
</programlisting>
The <function>DB_Table_Database::quote</function> method calls either the 
<function>DB::quoteSmart</function> or <function>MDB2::quote</function> 
method internally.  The return value is always a string, with a return 
value whose format depends upon the PHP type of $value: If $value is a 
string, the method returns a string that is properly quoted and escaped 
for the underlying RDBMS. If $value is an integer or float, it returns an 
unquoted string representation of the number. If $value is boolean, it 
returns '1' for true, or '0' for false (consistent with the representation 
of booleans as integers used by the <classname>DB_Table</classname> abstract 
data type). If $value is null, it returns the unquoted string NULL.
</para>
</refsect2>
<refsect2 id="package.database.db-table.intro-database.util.buildFilter">
<title><function>buildFilter</function></title>
<para>
<function>buildFilter</function> returns a SQL logical expression that 
is true if the values of a specified set of database columns are equal to 
a corresponding set of SQL literal values. It must be passed an array 
parameter in which the array keys are column names and the array values 
are the required values. 
</para><para>
The following example uses the buildFilter method to construct a filter 
for addresses on Pine St. in Peoria:
<programlisting role="php">
<![CDATA[
<?php
$data = array('Street' => 'Pine St', 'City' => 'Peoria');
$filter = $db->buildFilter($data);
?>
]]>
</programlisting>
Printing $filter then yields the SQL snippet:
<programlisting>
Street = 'Pine St' AND City = 'Peoria'
</programlisting>
In this example, the resulting SQL string is admittedly longer than 
the code required to create it. The function becomes more useful 
when the column names and/or values are variables representing data
of various types, rather than string literals, or strings that may
require escaping. The buildFilter method uses the quote method 
internally to construct SQL literal string representations of 
values.
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.util.buildSQL">
<title><function>buildSQL</function></title>
<para>
<function>buildSQL</function> - takes a query array of the form used by 
the select* methods, and returns a corresponding SQL command string. 
It is called internally by the <function>select*</function> methods. 
Both <function>buildSQL</function> and the <function>select*</function> 
methods are inherited from <classname>DB_Table_Base</classname>.
</para>
<para>
Synopsis: The interface is similar to that of the <function>select*</function> 
methods:
<programlisting>
<![CDATA[

string|PEAR_Error buildSQL(array|string $query, [string $filter], [string $order], 
                           [int $start], [int $count])

]]>
</programlisting>
As in the <function>select*</function> methods, $query is a query array or a key 
for a query array stored in the $sql property, $filter is an SQL logical condition 
that is added to the 'where' element of the query array, $order is an ORDER BY clause 
that overrides the 'order' element of the query array when it is present, and $start 
and $count are the first row in the result set that should be returned, and the 
maximum number of rows that should be returned. Only the $query argument is required. 
</para>
</refsect2>

<refsect2 id="package.database.db-table.intro-database.util.validCol">
<title><function>validCol</function></title>
<para>
<function>validCol</function> - validates and (if necessary) disambiguates 
column names. 
</para>
<para>
Synopsis:
<programlisting>
<![CDATA[

array|PEAR_Error validCol(string $col, [array $from])

]]>
</programlisting>
The required parameter $col is a column name. The optional $from parameter 
is a sequential array of table names.
</para>
<para>
The $col parameter may either be a column name qualified by a table name, 
using the SQL syntax table.column, or a column name that is not qualified 
by a table name, if the identification of the column with a table is 
unambiguous.  The return value of validCol, upon success, is a sequential 
array in which the second element is the unqualified column name string,
and the first element is either a table name (if $col is qualified by a 
table name or a unique table can be identified) or a sequential array of 
possible column names (if $col is an unqualified column name that could 
refer to columns in two or more different tables). If no column with the 
specified name exists in the database, a PEAR error is returned. 
</para>
<para>
The optional $from parameter is used only when $col is not explicitly 
qualified by a table name. When it is present, $from is a sequential 
list of tables that should be searched for a column of the specified 
name (as in the from clause of an SQL select statement). In this case, 
validCol first searches the tables in $from, and returns a table name 
if this yields a unique result. If a set of or more tables in $from 
are found to contain a column with the specified name, the return value 
is that set, or a subset thereof. If none of the table in $from contain
a columns with the specified name, the search is instead broadened to 
all tables in the database.  If two or more choices still remain at 
this point (either more than one tables in from, or more than one
tables in the rest of the database) the method tries excluding tables 
in which the specified column is a foreign key column, if this still 
leaves one or more tables in which the column is not a foreign key 
column.
</para>
</refsect2>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.modify"> 
<title>Data Modification: <function>insert</function>, 
       <function>update</function>, and <function>delete</function> 
</title>
<para>
The <function>insert</function>, <function>delete</function>, and 
<function>update</function> methods of <classname>DB_Table_Database</classname> 
have interfaces and behaviors similiar to those of the corresponding methods 
of DB_Table. The only differences in the interfaces are that each of these 
<classname>DB_Table_Database</classname> method requires an additional first 
parameter whose value is the name of the table to which the SQL insert, 
update, or delete command should be applied. 
</para>

<para>
Synopses:
<programlisting>
<![CDATA[

true|PEAR_Error insert(string $table, array $data)
true|PEAR_Error delete(string $table, [string $where])
true|PEAR_Error update(string $table, array $data, [string $where])

]]>
</programlisting>
In all three functions $table_name is the name of the table to which 
the operation should be applied. In the insert and update methods, 
$data is an associative array of data to be inserted or updated, in 
which the keys are column name strings and the values are the value 
to be inserted or updated in the database.  In the delete and update 
methods, the optional $where parameter is a string containing an SQL 
logical condition that is used to select the rows that should be 
deleted or updated, respectively.  That is, the $where parameter should 
contain the contents of the WHERE clause of the corresponding SQL 
command, without the 'WHERE ' prefix. Each method returns true on normal 
completion, and a PEAR Error if an error is encountered.
</para>

<para>
These <classname>DB_Table_Database</classname> methods are simple wrappers 
that call the corresponding methods <classname>DB_Table</classname> 
methods internally. As one result, overriding any of these methods in a 
subclass of <classname>DB_Table</classname> in order to customize the behavior 
of a specific table will automatically modify the behavior of the 
<classname>DB_Table_Database</classname> method.
</para>

<para>
The <classname>DB_Table_Database</classname> data 
<function>insert</function> and <function>update</function> methods can 
validate foreign key values before actually modifying data in the database, 
and can emulate referentially triggered actions such cascading deletes, if 
foreign key validation and these referentially triggered actions are enabled.
The corresponding methods of <classname>DB_Table</classname> will take 
identical actions if the <classname>DB_Table</classname> has been added to 
a parent <classname>DB_Table_Database</classname> object (i.e., if it 
contains a reference to a parent object), and if these actions are enabled 
in the parent <classname>DB_Table_Database</classname> object. Foreign key 
validation is disabled by default. Referentially triggered actions are 
enabled by default, for any such action that is declared in the database 
model.  
</para>

<para>
The <function>insert</function> and <function>update</function> methods return 
a <classname>PEAR_Error</classname> object if foreign key validation fails, or if 
an error occurs during any database command. A <classname>PEAR_Error</classname> 
is also returned if a 'restrict' ON DELETE or ON UPDATE action is declared, 
when such actions are enabled, if an attempt is made to delete or update any 
row that is referenced by a foreign key of one or more rows of another table.
</para>

</refsect1>

<refsect1 id="package.database.db-table.intro-database.serialize">
<title>PHP Serialization</title>
<para>
One way to maintain the state of <classname>DB_Table_Database</classname> 
between web pages is to serialize the entire database as one string, and 
save it in a session variable, a file, or a database. A serialized 
<classname>DB_Table_Database</classname> object contains serialized 
versions of all of its tables, and thus contains the information 
necessary to reconstruct the database. Serialization is accomplished 
by the PHP serialize function:
<programlisting role="php">
<![CDATA[
<?php
$db_serial = serialize($db);
?>
]]>
</programlisting>
The following two commands are necessary to unserialize and restore 
the state of a <classname>DB_Table_Database</classname> object:
<programlisting role="php">
<![CDATA[
<?php
$db = unserialize($db_serial);
$db->setDBconnection($DB_object);
?>
]]>
</programlisting>
where $DB_object is a DB or MDB2 connection object. 
The setDBconnection method sets the same database connection for the
parent <classname>DB_Table_Database</classname> object and all of 
the child <classname>DB_Table</classname> objects. 
</para>
<para>
When a <classname>DB_Table_Database</classname> object is unserialized, 
each child <classname>DB_Table</classname> 
object is unserialized in turn by the 
<function>DB_Table_Database::__wakeup</function> 
method.  If the <classname>DB_Table</classname> objects are instances 
of subclasses of <classname>DB_Table</classname>, this requires that 
the definitions of these subclasses exist in memory prior to 
unserialization of the table. This can be accomplished by explicitly 
including the file or files containing the required class definitions 
in the file containing the unserialize command, or by taking advantage 
of an auto-load mechanism that is built into the wake-up method.  
</para>
<para>
In order for autoloading of subclass definitions to work, each of the 
subclasses must be defined in a separate file in a default directory, 
with a filename that is given by the class name with an added '.php' 
extension.  If the definition of a required subclass of 
<classname>DB_Table</classname> named "classname" is found to not exist 
in memory when needed during unserialization, the 
<function>__wakeup</function> method tries to 
include a file named "classname.php" in this directory. 
</para><para>
For autoloading to work, the base of each such filename must be the 
class name obtained by applying the built-in get_class function to the 
object. This yields a lower case class name PHP 4 and preserves the 
capitalization used in the class definition in PHP 5. 
</para>
<refsect2 id="package.database.db-table.intro-database.serialize.setTableSubclassPath">
<title><function>setTableSubclassPath</function></title>
<para>
<function>setTableSubclassPath</function> - sets the path to the default 
directory for <classname>DB_Table</classname> subclass definitions.
</para> <para>
Synopsis:
<programlisting>
<![CDATA[

void setTableSubclassPath(string $path)

]]>
</programlisting>
Parameter $path is the path to the desired directory, without
a trailing directory separator. The path must be specified in
the form required by a 'require_once" statement, with the 
current PHP settings.
</para>
</refsect2>

</refsect1>

<refsect1 id="package.database.db-table.intro-database.xml">
<title>XML Serialization</title>
<para>
The <function>toXML</function> and <function>fromXML</function> 
methods may be used to serialize a database schema to, and unserialize 
it from, an XML string, respectively. The <function>fromXML</function> 
method uses simpleXML to parse the XML string, and so requires PHP 5. 
(This is the only method in the class that is not compatible with PHP 4). 
</para><para>
The XML schema used by these methods is an extension of the current
MDB2_Schema DTD, extended so as to allow specification of foreign 
key references. This extension for foreign keys has been agreed upon
for adoption in a future release of MDB2_Schema. 
</para><para>
The <function>toXML</function> method returns an XML string for the 
entire database,
including all of its tables and foreign key references, like so:
<programlisting role="php">
<![CDATA[
<?php
$xml_string = $db->toXML();
?>
]]>
</programlisting>
The <function>DB_Table_Database::fromXML</function> method is a static method 
that takes an MDB2 XML database schema string as its only parameter and returns 
a <classname>DB_Table_Database</classname> object containing all the tables 
and references in the database. The following pair of commands is necessary 
to create a <classname>DB_Table_Database</classname> object and connect it to 
a RDBMS
<programlisting role="php">
<![CDATA[<?php
$db = DB_Table_Database::fromXML($xml_string);
$db->setDBconnection($DB_object);
?>]]>
</programlisting> 
Here, as for unserialization, the <function>setDBconnection</function> 
method is used to establish a connection be the new object and a 
database server, where $DB_object is a DB or MDB2 connection object.  
The tables of the <classname>DB_Table_Database</classname> object that 
is returned by <function>fromXML</function> are all instances of 
<classname>DB_Table</classname> itself, rather than of custom subclasses 
of <classname>DB_Table</classname>.  <function>fromXML</function> returns 
a <classname>PEAR_Error</classname> if the XML string cannot be parsed, 
if an error is thrown during instantiation of either the 
<classname>DB_Table_Database</classname> object or any of the child 
<classname>DB_Table</classname> objects, or if called with a PHP 4 
interpreter (it requires PHP 5).  
</para>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.DBTableProps">
<title>Setting <classname>DB_Table</classname> properties</title>
<para>
Several methods of <classname>DB_Table_Database</classname> are used 
to set a common value of a <classname>DB_Table</classname> 
property for every child table in the database. These
methods, which have the same names and interfaces as the 
corresponding <classname>DB_Table</classname> methods, are:
<programlisting>
<![CDATA[

void autoValidInsert(bool $flag);
void autoValidUpdate(bool $flag);
void autoRecast(bool $flag);
void autoInc(bool $flag);

]]>
</programlisting>
Each has a boolean argument that turns on (true) or off (false) one 
of the features of <classname>DB_Table</classname>. All of the relevant 
features affect data insertion and updating, and are implemented within 
the <classname>DB_Table</classname>
<function>insert</function> and <function>update</function> methods.  
The <classname>DB_Table_Database</classname> <function>insert</function> 
and <function>update</function> methods simply call the corresponding
<classname>DB_Table</classname> methods, so changes in these properties 
also change the behavior of the <classname>DB_Table_Database</classname> 
methods. 
</para>
<para>
The autoValidInsert and autoValidUpdate methods turn on or off the 
automatic validation that data is of the expected type prior to 
insertion or updating of the data. The autoRecast method turns on 
or off the attempted recasting of data to the expected data type,
if necessary, prior to insertion or updating. autoInc turns on or 
off the PHP implementation of auto-incrementation of the value of
the $auto_inc_col column (if any) upon insertion. Note that, when
the feature is on, this column is still auto-incremented only if 
its value is left null in the data to be inserted.
</para>
</refsect1>

<refsect1 id="package.database.db-table.intro-database.get">
<title>Get* Methods</title>
<para>
Most of the properties of <classname>DB_Table_Database</classname> 
are private. A get* method is defined for each private property.  
Please see the API documentation for a discussion of all of properties 
and associated get* methods.
</para>
</refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../../../../manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.