| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.db.table">
- <title>Zend_Db_Table</title>
- <sect2 id="zend.db.table.introduction">
- <title>Introduction</title>
- <para>
- The <classname>Zend_Db_Table</classname> class is an object-oriented interface to
- database tables. It provides methods for many common operations on tables. The base
- class is extensible, so you can add custom logic.
- </para>
- <para>
- The <classname>Zend_Db_Table</classname> solution is an implementation of the
- <ulink url="http://www.martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
- Gateway</ulink> pattern. The solution also includes a class that implements the
- <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data
- Gateway</ulink> pattern.
- </para>
- </sect2>
- <sect2 id="zend.db.table.concrete">
- <title>Using Zend_Db_Table as a concrete class</title>
- <para>
- As of Zend Framework 1.9, you can instantiate <classname>Zend_Db_Table</classname>. This
- added benefit is that you do not have to extend a base class and configure it to do
- simple operations such as selecting, inserting, updating and deleteing on a single
- table. below is an example of the simplest of use cases.
- </para>
- <example id="zend.db.table.defining.concrete-instantiation.example1">
- <title>Declaring a table class with just the string name</title>
- <programlisting language="php"><![CDATA[
- Zend_Db_Table::setDefaultAdapter($dbAdapter);
- $bugTable = new Zend_Db_Table('bug');
- ]]></programlisting>
- </example>
- <para>
- The above example represents the simplest of use cases. Make not of all the
- options describe below for configuring <classname>Zend_Db_Table</classname> tables. If
- you want to be able to use the concrete usage case, in addition to the more complex
- relationhip features, see the <classname>Zend_Db_Table_Definition</classname>
- documentation.
- </para>
- </sect2>
- <sect2 id="zend.db.table.defining">
- <title>Defining a Table Class</title>
- <para>
- For each table in your database that you want to access, define a class that extends
- <classname>Zend_Db_Table_Abstract</classname>.
- </para>
- <sect3 id="zend.db.table.defining.table-schema">
- <title>Defining the Table Name and Schema</title>
- <para>
- Declare the database table for which this class is defined, using the protected
- variable <varname>$_name</varname>. This is a string, and must contain the name of
- the table spelled as it appears in the database.
- </para>
- <example id="zend.db.table.defining.table-schema.example1">
- <title>Declaring a table class with explicit table name</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- }
- ]]></programlisting>
- </example>
- <para>
- If you don't specify the table name, it defaults to the name of the class. If you
- rely on this default, the class name must match the spelling of the table name as
- it appears in the database.
- </para>
- <example id="zend.db.table.defining.table-schema.example">
- <title>Declaring a table class with implicit table name</title>
- <programlisting language="php"><![CDATA[
- class bugs extends Zend_Db_Table_Abstract
- {
- // table name matches class name
- }
- ]]></programlisting>
- </example>
- <para>
- You can also declare the schema for the table, either with the protected variable
- <varname>$_schema</varname>, or with the schema prepended to the table name in the
- <varname>$_name</varname> property. Any schema specified with the
- <varname>$_name</varname> property takes precedence over a schema specified with the
- <varname>$_schema</varname> property. In some <acronym>RDBMS</acronym> brands, the
- term for schema is "database" or "tablespace," but it is used similarly.
- </para>
- <example id="zend.db.table.defining.table-schema.example3">
- <title>Declaring a table class with schema</title>
- <programlisting language="php"><![CDATA[
- // First alternative:
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_schema = 'bug_db';
- protected $_name = 'bugs';
- }
- // Second alternative:
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bug_db.bugs';
- }
- // If schemas are specified in both $_name and $_schema, the one
- // specified in $_name takes precedence:
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bug_db.bugs';
- protected $_schema = 'ignored';
- }
- ]]></programlisting>
- </example>
- <para>
- The schema and table names may also be specified via constructor configuration
- directives, which override any default values specified with the
- <varname>$_name</varname> and <varname>$_schema</varname> properties. A schema
- specification given with the <property>name</property> directive overrides any value
- provided with the <property>schema</property> option.
- </para>
- <example id="zend.db.table.defining.table-schema.example.constructor">
- <title>Declaring table and schema names upon instantiation</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- }
- // First alternative:
- $tableBugs = new Bugs(array('name' => 'bugs', 'schema' => 'bug_db'));
- // Second alternative:
- $tableBugs = new Bugs(array('name' => 'bug_db.bugs'));
- // If schemas are specified in both 'name' and 'schema', the one
- // specified in 'name' takes precedence:
- $tableBugs = new Bugs(array('name' => 'bug_db.bugs',
- 'schema' => 'ignored'));
- ]]></programlisting>
- </example>
- <para>
- If you don't specify the schema name, it defaults to the schema to which your
- database adapter instance is connected.
- </para>
- </sect3>
- <sect3 id="zend.db.table.defining.primary-key">
- <title>Defining the Table Primary Key</title>
- <para>
- Every table must have a primary key. You can declare the column for the primary key
- using the protected variable <varname>$_primary</varname>. This is either a string
- that names the single column for the primary key, or else it is an array of column
- names if your primary key is a compound key.
- </para>
- <example id="zend.db.table.defining.primary-key.example">
- <title>Example of specifying the primary key</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_primary = 'bug_id';
- }
- ]]></programlisting>
- </example>
- <para>
- If you don't specify the primary key, <classname>Zend_Db_Table_Abstract</classname>
- tries to discover the primary key based on the information provided by the
- <methodname>describeTable()</methodname>´ method.
- </para>
- <note>
- <para>
- Every table class must know which columns can be used to address rows
- uniquely. If no primary key columns are specified in the table class
- definition or the table constructor arguments, or discovered in the table
- metadata provided by <methodname>describeTable()</methodname>, then the table
- cannot be used with <classname>Zend_Db_Table</classname>.
- </para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.defining.setup">
- <title>Overriding Table Setup Methods</title>
- <para>
- When you create an instance of a Table class, the constructor calls a set of
- protected methods that initialize metadata for the table. You can extend any of
- these methods to define metadata explicitly. Remember to call the method of the
- same name in the parent class at the end of your method.
- </para>
- <example id="zend.db.table.defining.setup.example">
- <title>Example of overriding the _setupTableName() method</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected function _setupTableName()
- {
- $this->_name = 'bugs';
- parent::_setupTableName();
- }
- }
- ]]></programlisting>
- </example>
- <para>
- The setup methods you can override are the following:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>_setupDatabaseAdapter()</methodname> checks that an adapter has
- been provided; gets a default adapter from the registry if needed. By
- overriding this method, you can set a database adapter from some other
- source.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>_setupTableName()</methodname> defaults the table name to the
- name of the class. By overriding this method, you can set the table name
- before this default behavior runs.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>_setupMetadata()</methodname> sets the schema if the table name
- contains the pattern "<command>schema.table</command>"; calls
- <methodname>describeTable()</methodname> to get metadata information;
- defaults the <varname>$_cols</varname> array to the columns reported by
- <methodname>describeTable()</methodname>. By overriding this method, you can
- specify the columns.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>_setupPrimaryKey()</methodname> defaults the primary key columns
- to those reported by <methodname>describeTable()</methodname>; checks that
- the primary key columns are included in the <varname>$_cols</varname> array.
- By overriding this method, you can specify the primary key columns.
- </para>
- </listitem>
- </itemizedlist>
- </sect3>
- <sect3 id="zend.db.table.initialization">
- <title>Table initialization</title>
- <para>
- If application-specific logic needs to be initialized when a Table class is
- constructed, you can select to move your tasks to the
- <methodname>init()</methodname> method, which is called after all Table metadata has
- been processed. This is recommended over the <methodname>__construct()</methodname>
- method if you do not need to alter the metadata in any programmatic way.
- </para>
- <example id="zend.db.table.defining.init.usage.example">
- <title>Example usage of init() method</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_observer;
- public function init()
- {
- $this->_observer = new MyObserverClass();
- }
- }
- ]]></programlisting>
- </example>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.constructing">
- <title>Creating an Instance of a Table</title>
- <para>
- Before you use a Table class, create an instance using its constructor. The
- constructor's argument is an array of options. The most important option to a Table
- constructor is the database adapter instance, representing a live connection to an
- <acronym>RDBMS</acronym>. There are three ways of specifying the database adapter to a
- Table class, and these three ways are described below:
- </para>
- <sect3 id="zend.db.table.constructing.adapter">
- <title>Specifying a Database Adapter</title>
- <para>
- The first way to provide a database adapter to a Table class is by passing it as an
- object of type <classname>Zend_Db_Adapter_Abstract</classname> in the options array,
- identified by the key '<property>db</property>'.
- </para>
- <example id="zend.db.table.constructing.adapter.example">
- <title>Example of constructing a Table using an Adapter object</title>
- <programlisting language="php"><![CDATA[
- $db = Zend_Db::factory('PDO_MYSQL', $options);
- $table = new Bugs(array('db' => $db));
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.constructing.default-adapter">
- <title>Setting a Default Database Adapter</title>
- <para>
- The second way to provide a database adapter to a Table class is by declaring an
- object of type <classname>Zend_Db_Adapter_Abstract</classname> to be a default
- database adapter for all subsequent instances of Tables in your application. You can
- do this with the static method
- <methodname>Zend_Db_Table_Abstract::setDefaultAdapter()</methodname>. The argument
- is an object of type <classname>Zend_Db_Adapter_Abstract</classname>.
- </para>
- <example id="zend.db.table.constructing.default-adapter.example">
- <title>Example of constructing a Table using a the Default Adapter</title>
- <programlisting language="php"><![CDATA[
- $db = Zend_Db::factory('PDO_MYSQL', $options);
- Zend_Db_Table_Abstract::setDefaultAdapter($db);
- // Later...
- $table = new Bugs();
- ]]></programlisting>
- </example>
- <para>
- It can be convenient to create the database adapter object in a central place of
- your application, such as the bootstrap, and then store it as the default adapter.
- This gives you a means to ensure that the adapter instance is the same throughout
- your application. However, setting a default adapter is limited to a single adapter
- instance.
- </para>
- </sect3>
- <sect3 id="zend.db.table.constructing.registry">
- <title>Storing a Database Adapter in the Registry</title>
- <para>
- The third way to provide a database adapter to a Table class is by passing a string
- in the options array, also identified by the '<property>db</property>' key. The
- string is used as a key to the static <classname>Zend_Registry</classname> instance,
- where the entry at that key is an object of type
- <classname>Zend_Db_Adapter_Abstract</classname>.
- </para>
- <example id="zend.db.table.constructing.registry.example">
- <title>Example of constructing a Table using a Registry key</title>
- <programlisting language="php"><![CDATA[
- $db = Zend_Db::factory('PDO_MYSQL', $options);
- Zend_Registry::set('my_db', $db);
- // Later...
- $table = new Bugs(array('db' => 'my_db'));
- ]]></programlisting>
- </example>
- <para>
- Like setting the default adapter, this gives you the means to ensure that the same
- adapter instance is used throughout your application. Using the registry is more
- flexible, because you can store more than one adapter instance. A given adapter
- instance is specific to a certain <acronym>RDBMS</acronym> brand and database
- instance. If your application needs access to multiple databases or even multiple
- database brands, then you need to use multiple adapters.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.insert">
- <title>Inserting Rows to a Table</title>
- <para>
- You can use the Table object to insert rows into the database table on which the Table
- object is based. Use the <methodname>insert()</methodname> method of your Table object.
- The argument is an associative array, mapping column names to values.
- </para>
- <example id="zend.db.table.insert.example">
- <title>Example of inserting to a Table</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $data = array(
- 'created_on' => '2007-03-22',
- 'bug_description' => 'Something wrong',
- 'bug_status' => 'NEW'
- );
- $table->insert($data);
- ]]></programlisting>
- </example>
- <para>
- By default, the values in your data array are inserted as literal values, using
- parameters. If you need them to be treated as <acronym>SQL</acronym> expressions, you
- must make sure they are distinct from plain strings. Use an object of type
- <classname>Zend_Db_Expr</classname> to do this.
- </para>
- <example id="zend.db.table.insert.example-expr">
- <title>Example of inserting expressions to a Table</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $data = array(
- 'created_on' => new Zend_Db_Expr('CURDATE()'),
- 'bug_description' => 'Something wrong',
- 'bug_status' => 'NEW'
- );
- ]]></programlisting>
- </example>
- <para>
- In the examples of inserting rows above, it is assumed that the table has an
- auto-incrementing primary key. This is the default behavior of
- <classname>Zend_Db_Table_Abstract</classname>, but there are other types of primary keys
- as well. The following sections describe how to support different types of primary keys.
- </para>
- <sect3 id="zend.db.table.insert.key-auto">
- <title>Using a Table with an Auto-incrementing Key</title>
- <para>
- An auto-incrementing primary key generates a unique integer value for you if you
- omit the primary key column from your <acronym>SQL</acronym>
- <constant>INSERT</constant> statement.
- </para>
- <para>
- In <classname>Zend_Db_Table_Abstract</classname>, if you define the protected
- variable <varname>$_sequence</varname> to be the Boolean value
- <constant>TRUE</constant>, then the class assumes that the table has an
- auto-incrementing primary key.
- </para>
- <example id="zend.db.table.insert.key-auto.example">
- <title>Example of declaring a Table with auto-incrementing primary key</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- // This is the default in the Zend_Db_Table_Abstract class;
- // you do not need to define this.
- protected $_sequence = true;
- }
- ]]></programlisting>
- </example>
- <para>
- MySQL, Microsoft <acronym>SQL</acronym> Server, and SQLite are examples of
- <acronym>RDBMS</acronym> brands that support auto-incrementing primary keys.
- </para>
- <para>
- PostgreSQL has a <constant>SERIAL</constant> notation that implicitly defines a
- sequence based on the table and column name, and uses the sequence to generate key
- values for new rows. <acronym>IBM</acronym> <acronym>DB2</acronym> has an
- <constant>IDENTITY</constant> notation that works similarly. If you use either of
- these notations, treat your <classname>Zend_Db_Table</classname> class as having an
- auto-incrementing column with respect to declaring the <varname>$_sequence</varname>
- member as <constant>TRUE</constant>.
- </para>
- </sect3>
- <sect3 id="zend.db.table.insert.key-sequence">
- <title>Using a Table with a Sequence</title>
- <para>
- A sequence is a database object that generates a unique value, which can be used
- as a primary key value in one or more tables of the database.
- </para>
- <para>
- If you define <varname>$_sequence</varname> to be a string, then
- <classname>Zend_Db_Table_Abstract</classname> assumes the string to name a sequence
- object in the database. The sequence is invoked to generate a new value, and this
- value is used in the <constant>INSERT</constant> operation.
- </para>
- <example id="zend.db.table.insert.key-sequence.example">
- <title>Example of declaring a Table with a sequence</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_sequence = 'bug_sequence';
- }
- ]]></programlisting>
- </example>
- <para>
- Oracle, PostgreSQL, and <acronym>IBM</acronym> <acronym>DB2</acronym> are examples
- of <acronym>RDBMS</acronym> brands that support sequence objects in the database.
- </para>
- <para>
- PostgreSQL and <acronym>IBM</acronym> <acronym>DB2</acronym> also have syntax that
- defines sequences implicitly and associated with columns. If you use this notation,
- treat the table as having an auto-incrementing key column. Define the sequence name
- as a string only in cases where you would invoke the sequence explicitly to get the
- next key value.
- </para>
- </sect3>
- <sect3 id="zend.db.table.insert.key-natural">
- <title>Using a Table with a Natural Key</title>
- <para>
- Some tables have a natural key. This means that the key is not automatically
- generated by the table or by a sequence. You must specify the value for the primary
- key in this case.
- </para>
- <para>
- If you define the <varname>$_sequence</varname> to be the Boolean value
- <constant>FALSE</constant>, then <classname>Zend_Db_Table_Abstract</classname>
- assumes that the table has a natural primary key. You must provide values for the
- primary key columns in the array of data to the <methodname>insert()</methodname>
- method, or else this method throws a <classname>Zend_Db_Table_Exception</classname>.
- </para>
- <example id="zend.db.table.insert.key-natural.example">
- <title>Example of declaring a Table with a natural key</title>
- <programlisting language="php"><![CDATA[
- class BugStatus extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bug_status';
- protected $_sequence = false;
- }
- ]]></programlisting>
- </example>
- <note>
- <para>
- All <acronym>RDBMS</acronym> brands support tables with natural keys. Examples
- of tables that are often declared as having natural keys are lookup tables,
- intersection tables in many-to-many relationships, or most tables with compound
- primary keys.
- </para>
- </note>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.update">
- <title>Updating Rows in a Table</title>
- <para>
- You can update rows in a database table using the <methodname>update()</methodname>
- method of a Table class. This method takes two arguments: an associative array of
- columns to change and new values to assign to these columns; and an
- <acronym>SQL</acronym> expression that is used in a <constant>WHERE</constant> clause,
- as criteria for the rows to change in the <constant>UPDATE</constant> operation.
- </para>
- <example id="zend.db.table.update.example">
- <title>Example of updating rows in a Table</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $data = array(
- 'updated_on' => '2007-03-23',
- 'bug_status' => 'FIXED'
- );
- $where = $table->getAdapter()->quoteInto('bug_id = ?', 1234);
- $table->update($data, $where);
- ]]></programlisting>
- </example>
- <para>
- Since the table <methodname>update()</methodname> method proxies to the database adapter
- <link linkend="zend.db.adapter.write.update"><methodname>update()</methodname></link>
- method, the second argument can be an array of <acronym>SQL</acronym> expressions. The
- expressions are combined as Boolean terms using an <constant>AND</constant> operator.
- </para>
- <note>
- <para>
- The values and identifiers in the <acronym>SQL</acronym> expression are not quoted
- for you. If you have values or identifiers that require quoting, you are responsible
- for doing this. Use the <methodname>quote()</methodname>,
- <methodname>quoteInto()</methodname>, and <methodname>quoteIdentifier()</methodname>
- methods of the database adapter.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.db.table.delete">
- <title>Deleting Rows from a Table</title>
- <para>
- You can delete rows from a database table using the <methodname>delete()</methodname>
- method. This method takes one argument, which is an <acronym>SQL</acronym> expression
- that is used in a <constant>WHERE</constant> clause, as criteria for the rows to delete.
- </para>
- <example id="zend.db.table.delete.example">
- <title>Example of deleting rows from a Table</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);
- $table->delete($where);
- ]]></programlisting>
- </example>
- <para>
- Since the table <methodname>delete()</methodname> method proxies to the database adapter
- <link linkend="zend.db.adapter.write.delete"><methodname>delete()</methodname></link>
- method, the argument can also be an array of <acronym>SQL</acronym> expressions. The
- expressions are combined as Boolean terms using an <constant>AND</constant> operator.
- </para>
- <note>
- <para>
- The values and identifiers in the <acronym>SQL</acronym> expression are not quoted
- for you. If you have values or identifiers that require quoting, you are responsible
- for doing this. Use the <methodname>quote()</methodname>,
- <methodname>quoteInto()</methodname>, and <methodname>quoteIdentifier()</methodname>
- methods of the database adapter.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.db.table.find">
- <title>Finding Rows by Primary Key</title>
- <para>
- You can query the database table for rows matching specific values in the primary key,
- using the <methodname>find()</methodname> method. The first argument of this method is
- either a single value or an array of values to match against the primary key of the
- table.
- </para>
- <example id="zend.db.table.find.example">
- <title>Example of finding rows by primary key values</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- // Find a single row
- // Returns a Rowset
- $rows = $table->find(1234);
- // Find multiple rows
- // Also returns a Rowset
- $rows = $table->find(array(1234, 5678));
- ]]></programlisting>
- </example>
- <para>
- If you specify a single value, the method returns at most one row, because a primary
- key cannot have duplicate values and there is at most one row in the database table
- matching the value you specify. If you specify multiple values in an array, the method
- returns at most as many rows as the number of distinct values you specify.
- </para>
- <para>
- The <methodname>find()</methodname> method might return fewer rows than the number of
- values you specify for the primary key, if some of the values don't match any rows in
- the database table. The method even may return zero rows. Because the number of rows
- returned is variable, the <methodname>find()</methodname> method returns an object of
- type <classname>Zend_Db_Table_Rowset_Abstract</classname>.
- </para>
- <para>
- If the primary key is a compound key, that is, it consists of multiple columns, you can
- specify the additional columns as additional arguments to the
- <methodname>find()</methodname> method. You must provide as many arguments as the number
- of columns in the table's primary key.
- </para>
- <para>
- To find multiple rows from a table with a compound primary key, provide an array for
- each of the arguments. All of these arrays must have the same number of elements. The
- values in each array are formed into tuples in order; for example, the first element
- in all the array arguments define the first compound primary key value, then the second
- elements of all the arrays define the second compound primary key value, and so on.
- </para>
- <example id="zend.db.table.find.example-compound">
- <title>Example of finding rows by compound primary key values</title>
- <para>
- The call to <methodname>find()</methodname> below to match multiple rows can match
- two rows in the database. The first row must have primary key value (1234, 'ABC'),
- and the second row must have primary key value (5678, 'DEF').
- </para>
- <programlisting language="php"><![CDATA[
- class BugsProducts extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs_products';
- protected $_primary = array('bug_id', 'product_id');
- }
- $table = new BugsProducts();
- // Find a single row with a compound primary key
- // Returns a Rowset
- $rows = $table->find(1234, 'ABC');
- // Find multiple rows with compound primary keys
- // Also returns a Rowset
- $rows = $table->find(array(1234, 5678), array('ABC', 'DEF'));
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.fetch-all">
- <title>Querying for a Set of Rows</title>
- <sect3 id="zend.db.table.fetch-all.select">
- <title>Select API</title>
- <warning>
- <para>
- The <acronym>API</acronym> for fetch operations has been superseded to allow
- a <classname>Zend_Db_Table_Select</classname> object to modify the query.
- However, the deprecated usage of the <methodname>fetchRow()</methodname> and
- <methodname>fetchAll()</methodname> methods will continue to work without
- modification.
- </para>
- <para>
- The following statements are all legal and functionally identical, however
- it is recommended to update your code to take advantage of the new usage
- where possible.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Fetching a rowset
- */
- $rows = $table->fetchAll(
- 'bug_status = "NEW"',
- 'bug_id ASC',
- 10,
- 0
- );
- $rows = $table->fetchAll(
- $table->select()
- ->where('bug_status = ?', 'NEW')
- ->order('bug_id ASC')
- ->limit(10, 0)
- );
- // or with binding
- $rows = $table->fetchAll(
- $table->select()
- ->where('bug_status = :status')
- ->bind(array(':status'=>'NEW')
- ->order('bug_id ASC')
- ->limit(10, 0)
- );
- /**
- * Fetching a single row
- */
- $row = $table->fetchRow(
- 'bug_status = "NEW"',
- 'bug_id ASC'
- );
- $row = $table->fetchRow(
- $table->select()
- ->where('bug_status = ?', 'NEW')
- ->order('bug_id ASC')
- );
- // or with binding
- $row = $table->fetchRow(
- $table->select()
- ->where('bug_status = :status')
- ->bind(array(':status'=>'NEW')
- ->order('bug_id ASC')
- );
- ]]></programlisting>
- </warning>
- <para>
- The <classname>Zend_Db_Table_Select</classname> object is an extension of the
- <classname>Zend_Db_Select</classname> object that applies specific restrictions to
- a query. The enhancements and restrictions are:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- You <emphasis>can</emphasis> elect to return a subset of columns within a
- fetchRow or fetchAll query. This can provide optimization benefits where
- returning a large set of results for all columns is not desirable.
- </para>
- </listitem>
- <listitem>
- <para>
- You <emphasis>can</emphasis> specify columns that evaluate expressions from
- within the selected table. However this will mean that the returned row or
- rowset will be <property>readOnly</property> and cannot be used for
- <methodname>save()</methodname> operations. A
- <classname>Zend_Db_Table_Row</classname> with
- <property>readOnly</property> status will throw an exception if a
- <methodname>save()</methodname> operation is attempted.
- </para>
- </listitem>
- <listitem>
- <para>
- You <emphasis>can</emphasis> allow <constant>JOIN</constant> clauses on a
- select to allow multi-table lookups.
- </para>
- </listitem>
- <listitem>
- <para>
- You <emphasis>can not</emphasis> specify columns from a JOINed tabled to be
- returned in a row or rowset. Doing so will trigger a <acronym>PHP</acronym>
- error. This was done to ensure the integrity of the
- <classname>Zend_Db_Table</classname> is retained. i.e. A
- <classname>Zend_Db_Table_Row</classname> should only reference columns
- derived from its parent table.
- </para>
- </listitem>
- </itemizedlist>
- <example id="zend.db.table.qry.rows.set.simple.usage.example">
- <title>Simple usage</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select();
- $select->where('bug_status = ?', 'NEW');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <para>
- Fluent interfaces are implemented across the component, so this can be rewritten
- this in a more abbreviated form.
- </para>
- <example id="zend.db.table.qry.rows.set.fluent.interface.example">
- <title>Example of fluent interface</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $rows =
- $table->fetchAll($table->select()->where('bug_status = ?', 'NEW'));
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.fetch-all.usage">
- <title>Fetching a rowset</title>
- <para>
- You can query for a set of rows using any criteria other than the primary key
- values, using the <methodname>fetchAll()</methodname> method of the Table class.
- This method returns an object of type
- <classname>Zend_Db_Table_Rowset_Abstract</classname>.
- </para>
- <example id="zend.db.table.qry.rows.set.finding.row.example">
- <title>Example of finding rows by an expression</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select()->where('bug_status = ?', 'NEW');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <para>
- You may also pass sorting criteria in an <constant>ORDER</constant> BY clause, as
- well as count and offset integer values, used to make the query return a specific
- subset of rows. These values are used in a <constant>LIMIT</constant> clause, or in
- equivalent logic for <acronym>RDBMS</acronym> brands that do not support the
- <constant>LIMIT</constant> syntax.
- </para>
- <example id="zend.db.table.fetch-all.example2">
- <title>Example of finding rows by an expression</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $order = 'bug_id';
- // Return the 21st through 30th rows
- $count = 10;
- $offset = 20;
- $select = $table->select()->where('bug_status = ?', 'NEW')
- ->order($order)
- ->limit($count, $offset);
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <para>
- All of the arguments above are optional. If you omit the <constant>ORDER</constant>
- clause, the result set includes rows from the table in an unpredictable order. If
- no <constant>LIMIT</constant> clause is set, you retrieve every row in the table
- that matches the <constant>WHERE</constant> clause.
- </para>
- </sect3>
- <sect3 id="zend.db.table.advanced.usage">
- <title>Advanced usage</title>
- <para>
- For more specific and optimized requests, you may wish to limit the number of
- columns returned in a row or rowset. This can be achieved by passing a
- <constant>FROM</constant> clause to the select object. The first argument in the
- <constant>FROM</constant> clause is identical to that of a
- <classname>Zend_Db_Select</classname> object with the addition of being able to pass
- an instance of <classname>Zend_Db_Table_Abstract</classname> and have it
- automatically determine the table name.
- </para>
- <example id="zend.db.table.qry.rows.set.retrieving.a.example">
- <title>Retrieving specific columns</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select();
- $select->from($table, array('bug_id', 'bug_description'))
- ->where('bug_status = ?', 'NEW');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <important>
- <para>
- The rowset contains rows that are still 'valid' - they simply contain a
- subset of the columns of a table. If a <methodname>save()</methodname>
- method is called on a partial row then only the fields available will be
- modified.
- </para>
- </important>
- <para>
- You can also specify expressions within a <constant>FROM</constant> clause and have
- these returned as a readOnly row or rowset. In this example we will return a rows
- from the bugs table that show an aggregate of the number of new bugs reported by
- individuals. Note the <constant>GROUP</constant> clause. The 'count' column will be
- made available to the row for evaluation and can be accessed as if it were part of
- the schema.
- </para>
- <example id="zend.db.table.qry.rows.set.retrieving.b.example">
- <title>Retrieving expressions as columns</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select();
- $select->from($table,
- array('COUNT(reported_by) as `count`', 'reported_by'))
- ->where('bug_status = ?', 'NEW')
- ->group('reported_by');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <para>
- You can also use a lookup as part of your query to further refine your fetch
- operations. In this example the accounts table is queried as part of a search for
- all new bugs reported by 'Bob'.
- </para>
- <example id="zend.db.table.qry.rows.set.refine.example">
- <title>Using a lookup table to refine the results of fetchAll()</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- // retrieve with from part set, important when joining
- $select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
- $select->setIntegrityCheck(false)
- ->where('bug_status = ?', 'NEW')
- ->join('accounts', 'accounts.account_name = bugs.reported_by')
- ->where('accounts.account_name = ?', 'Bob');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- <para>
- The <classname>Zend_Db_Table_Select</classname> is primarily used to constrain and
- validate so that it may enforce the criteria for a legal <constant>SELECT</constant>
- query. However there may be certain cases where you require the flexibility of the
- <classname>Zend_Db_Table_Row</classname> component and do not require a writable or
- deletable row. for this specific user case, it is possible to retrieve a row or
- rowset by passing a <constant>FALSE</constant> value to
- <methodname>setIntegrityCheck()</methodname>. The resulting row or rowset will be
- returned as a 'locked' row (meaning the <methodname>save()</methodname>,
- <methodname>delete()</methodname> and any field-setting methods will throw an
- exception).
- </para>
- <example id="zend.db.table.qry.rows.set.integrity.example">
- <title>
- Removing the integrity check on Zend_Db_Table_Select to allow JOINed rows
- </title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
- ->setIntegrityCheck(false);
- $select->where('bug_status = ?', 'NEW')
- ->join('accounts',
- 'accounts.account_name = bugs.reported_by',
- 'account_name')
- ->where('accounts.account_name = ?', 'Bob');
- $rows = $table->fetchAll($select);
- ]]></programlisting>
- </example>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.fetch-row">
- <title>Querying for a Single Row</title>
- <para>
- You can query for a single row using criteria similar to that of the
- <methodname>fetchAll()</methodname> method.
- </para>
- <example id="zend.db.table.fetch-row.example1">
- <title>Example of finding a single row by an expression</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $select = $table->select()->where('bug_status = ?', 'NEW')
- ->order('bug_id');
- $row = $table->fetchRow($select);
- ]]></programlisting>
- </example>
- <para>
- This method returns an object of type <classname>Zend_Db_Table_Row_Abstract</classname>.
- If the search criteria you specified match no rows in the database table, then
- <methodname>fetchRow()</methodname> returns <acronym>PHP</acronym>'s
- <constant>NULL</constant> value.
- </para>
- </sect2>
- <sect2 id="zend.db.table.info">
- <title>Retrieving Table Metadata Information</title>
- <para>
- The <classname>Zend_Db_Table_Abstract</classname> class provides some information about
- its metadata. The <methodname>info()</methodname> method returns an array structure with
- information about the table, its columns and primary key, and other metadata.
- </para>
- <example id="zend.db.table.info.example">
- <title>Example of getting the table name</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $info = $table->info();
- echo "The table name is " . $info['name'] . "\n";
- ]]></programlisting>
- </example>
- <para>
- The keys of the array returned by the <methodname>info()</methodname> method are
- described below:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>name</emphasis> => the name of the table.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>cols</emphasis> => an array, naming the columns of
- the table.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>primary</emphasis> => an array, naming the columns in
- the primary key.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>metadata</emphasis> => an associative array, mapping
- column names to information about the columns. This is the information returned
- by the <methodname>describeTable()</methodname> method.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>rowClass</emphasis> => the name of the concrete class
- used for Row objects returned by methods of this table instance. This defaults
- to <classname>Zend_Db_Table_Row</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>rowsetClass</emphasis> => the name of the concrete
- class used for Rowset objects returned by methods of this table instance. This
- defaults to <classname>Zend_Db_Table_Rowset</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>referenceMap</emphasis> => an associative array, with
- information about references from this table to any parent tables. See
- <link linkend="zend.db.table.relationships.defining">this chapter</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>dependentTables</emphasis> => an array of class names
- of tables that reference this table. See
- <link linkend="zend.db.table.relationships.defining">this chapter</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>schema</emphasis> => the name of the schema (or
- database or tablespace) for this table.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.db.table.metadata.caching">
- <title>Caching Table Metadata</title>
- <para>
- By default, <classname>Zend_Db_Table_Abstract</classname> queries the
- underlying database for <link linkend="zend.db.table.info">table
- metadata</link> whenever that data is needed to perform table
- operations. The table object fetches the table metadata from the
- database using the adapter's <methodname>describeTable()</methodname> method.
- Operations requiring this introspection include:
- </para>
- <itemizedlist>
- <listitem><para><methodname>insert()</methodname></para></listitem>
- <listitem><para><methodname>find()</methodname></para></listitem>
- <listitem><para><methodname>info()</methodname></para></listitem>
- </itemizedlist>
- <para>
- In some circumstances, particularly when many table objects are instantiated against
- the same database table, querying the database for the table metadata for each instance
- may be undesirable from a performance standpoint. In such cases, users may benefit by
- caching the table metadata retrieved from the database.
- </para>
- <para>
- There are two primary ways in which a user may take advantage of table metadata
- caching:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Call
- <methodname>Zend_Db_Table_Abstract::setDefaultMetadataCache()</methodname></emphasis>
- - This allows a developer to once set the default cache object to be used
- for all table classes.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Configure
- <methodname>Zend_Db_Table_Abstract::__construct()</methodname></emphasis> -
- This allows a developer to set the cache object to be used for a particular
- table class instance.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- In both cases, the cache specification must be either <constant>NULL</constant> (i.e.,
- no cache used) or an instance of
- <link linkend="zend.cache.frontends.core"><classname>Zend_Cache_Core</classname></link>.
- The methods may be used in conjunction when it is desirable to have both a default
- metadata cache and the ability to change the cache for individual table objects.
- </para>
- <example id="zend.db.table.metadata.caching-default">
- <title>Using a Default Metadata Cache for all Table Objects</title>
- <para>
- The following code demonstrates how to set a default metadata cache to be used for
- all table objects:
- </para>
- <programlisting language="php"><![CDATA[
- // First, set up the Cache
- $frontendOptions = array(
- 'automatic_serialization' => true
- );
- $backendOptions = array(
- 'cache_dir' => 'cacheDir'
- );
- $cache = Zend_Cache::factory('Core',
- 'File',
- $frontendOptions,
- $backendOptions);
- // Next, set the cache to be used with all table objects
- Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
- // A table class is also needed
- class Bugs extends Zend_Db_Table_Abstract
- {
- // ...
- }
- // Each instance of Bugs now uses the default metadata cache
- $bugs = new Bugs();
- ]]></programlisting>
- </example>
- <example id="zend.db.table.metadata.caching-instance">
- <title>Using a Metadata Cache for a Specific Table Object</title>
- <para>
- The following code demonstrates how to set a metadata cache for a specific table
- object instance:
- </para>
- <programlisting language="php"><![CDATA[
- // First, set up the Cache
- $frontendOptions = array(
- 'automatic_serialization' => true
- );
- $backendOptions = array(
- 'cache_dir' => 'cacheDir'
- );
- $cache = Zend_Cache::factory('Core',
- 'File',
- $frontendOptions,
- $backendOptions);
- // A table class is also needed
- class Bugs extends Zend_Db_Table_Abstract
- {
- // ...
- }
- // Configure an instance upon instantiation
- $bugs = new Bugs(array('metadataCache' => $cache));
- ]]></programlisting>
- </example>
- <note>
- <title>Automatic Serialization with the Cache Frontend</title>
- <para>
- Since the information returned from the adapter's
- <methodname>describeTable()</methodname> method is an array, ensure that the
- <property>automatic_serialization</property> option is set to
- <constant>TRUE</constant> for the <classname>Zend_Cache_Core</classname> frontend.
- </para>
- </note>
- <para>
- Though the above examples use <classname>Zend_Cache_Backend_File</classname>, developers
- may use whatever cache backend is appropriate for the situation. Please see
- <link linkend="zend.cache">Zend_Cache</link> for more information.
- </para>
- <sect3 id="zend.db.table.metadata.caching.hardcoding">
- <title>Hardcoding Table Metadata</title>
- <para>
- To take metadata caching a step further, you can also choose to
- hardcode metadata. In this particular case, however, any changes
- to the table schema will require a change in your code. As such,
- it is only recommended for those who are optimizing for
- production usage.
- </para>
- <para>
- The metadata structure is as follows:
- </para>
- <programlisting language="php"><![CDATA[
- protected $_metadata = array(
- '<column_name>' => array(
- 'SCHEMA_NAME' => <string>,
- 'TABLE_NAME' => <string>,
- 'COLUMN_NAME' => <string>,
- 'COLUMN_POSITION' => <int>,
- 'DATA_TYPE' => <string>,
- 'DEFAULT' => NULL|<value>,
- 'NULLABLE' => <bool>,
- 'LENGTH' => <string - length>,
- 'SCALE' => NULL|<value>,
- 'PRECISION' => NULL|<value>,
- 'UNSIGNED' => NULL|<bool>,
- 'PRIMARY' => <bool>,
- 'PRIMARY_POSITION' => <int>,
- 'IDENTITY' => <bool>,
- ),
- // additional columns...
- );
- ]]></programlisting>
- <para>
- An easy way to get the appropriate values is to use the metadata
- cache, and then to deserialize values stored in the cache.
- </para>
- <para>
- You can disable this optimization by turning of the
- <property>metadataCacheInClass</property> flag:
- </para>
- <programlisting language="php"><![CDATA[
- // At instantiation:
- $bugs = new Bugs(array('metadataCacheInClass' => false));
- // Or later:
- $bugs->setMetadataCacheInClass(false);
- ]]></programlisting>
- <para>
- The flag is enabled by default, which ensures that the
- <varname>$_metadata</varname> array is only populated once per
- instance.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.extending">
- <title>Customizing and Extending a Table Class</title>
- <sect3 id="zend.db.table.extending.row-rowset">
- <title>Using Custom Row or Rowset Classes</title>
- <para>
- By default, methods of the Table class return a Rowset in instances of the concrete
- class <classname>Zend_Db_Table_Rowset</classname>, and Rowsets contain a collection
- of instances of the concrete class <classname>Zend_Db_Table_Row</classname> You can
- specify an alternative class to use for either of these, but they must be classes
- that extend <classname>Zend_Db_Table_Rowset_Abstract</classname> and
- <classname>Zend_Db_Table_Row_Abstract</classname>, respectively.
- </para>
- <para>
- You can specify Row and Rowset classes using the Table constructor's options array,
- in keys '<property>rowClass</property>' and '<property>rowsetClass</property>'
- respectively. Specify the names of the classes using strings.
- </para>
- <example id="zend.db.table.extending.row-rowset.example">
- <title>Example of specifying the Row and Rowset classes</title>
- <programlisting language="php"><![CDATA[
- class My_Row extends Zend_Db_Table_Row_Abstract
- {
- ...
- }
- class My_Rowset extends Zend_Db_Table_Rowset_Abstract
- {
- ...
- }
- $table = new Bugs(
- array(
- 'rowClass' => 'My_Row',
- 'rowsetClass' => 'My_Rowset'
- )
- );
- $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
- // Returns an object of type My_Rowset,
- // containing an array of objects of type My_Row.
- $rows = $table->fetchAll($where);
- ]]></programlisting>
- </example>
- <para>
- You can change the classes by specifying them with the
- <methodname>setRowClass()</methodname> and <methodname>setRowsetClass()</methodname>
- methods. This applies to rows and rowsets created subsequently; it does not change
- the class of any row or rowset objects you have created previously.
- </para>
- <example id="zend.db.table.extending.row-rowset.example2">
- <title>Example of changing the Row and Rowset classes</title>
- <programlisting language="php"><![CDATA[
- $table = new Bugs();
- $where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')
- // Returns an object of type Zend_Db_Table_Rowset
- // containing an array of objects of type Zend_Db_Table_Row.
- $rowsStandard = $table->fetchAll($where);
- $table->setRowClass('My_Row');
- $table->setRowsetClass('My_Rowset');
- // Returns an object of type My_Rowset,
- // containing an array of objects of type My_Row.
- $rowsCustom = $table->fetchAll($where);
- // The $rowsStandard object still exists, and it is unchanged.
- ]]></programlisting>
- </example>
- <para>
- For more information on the Row and Rowset classes, see
- <link linkend="zend.db.table.row">this chapter</link> and <link
- linkend="zend.db.table.rowset">this one</link>.
- </para>
- </sect3>
- <sect3 id="zend.db.table.extending.insert-update">
- <title>Defining Custom Logic for Insert, Update, and Delete</title>
- <para>
- You can override the <methodname>insert()</methodname> and
- <methodname>update()</methodname> methods in your Table class. This gives you the
- opportunity to implement custom code that is executed before performing the database
- operation. Be sure to call the parent class method when you are done.
- </para>
- <example id="zend.db.table.extending.insert-update.example">
- <title>Custom logic to manage timestamps</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- public function insert(array $data)
- {
- // add a timestamp
- if (empty($data['created_on'])) {
- $data['created_on'] = time();
- }
- return parent::insert($data);
- }
- public function update(array $data, $where)
- {
- // add a timestamp
- if (empty($data['updated_on'])) {
- $data['updated_on'] = time();
- }
- return parent::update($data, $where);
- }
- }
- ]]></programlisting>
- </example>
- <para>
- You can also override the <methodname>delete()</methodname> method.
- </para>
- </sect3>
- <sect3 id="zend.db.table.extending.finders">
- <title>Define Custom Search Methods in Zend_Db_Table</title>
- <para>
- You can implement custom query methods in your Table class, if you have frequent
- need to do queries against this table with specific criteria. Most queries can be
- written using <methodname>fetchAll()</methodname>, but this requires that you
- duplicate code to form the query conditions if you need to run the query in several
- places in your application. Therefore it can be convenient to implement a method in
- the Table class to perform frequently-used queries against this table.
- </para>
- <example id="zend.db.table.extending.finders.example">
- <title>Custom method to find bugs by status</title>
- <programlisting language="php"><![CDATA[
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- public function findByStatus($status)
- {
- $where = $this->getAdapter()->quoteInto('bug_status = ?', $status);
- return $this->fetchAll($where, 'bug_id');
- }
- }
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.extending.inflection">
- <title>Define Inflection in Zend_Db_Table</title>
- <para>
- Some people prefer that the table class name match a table name in the
- <acronym>RDBMS</acronym> by using a string transformation called
- <emphasis>inflection</emphasis>.
- </para>
- <para>
- For example, if your table class name is "BugsProducts", it would
- match the physical table in the database called "bugs_products", if
- you omit the explicit declaration of the <varname>$_name</varname> class property.
- In this inflection mapping, the class name spelled in "CamelCase" format would be
- transformed to lower case, and words are separated with an underscore.
- </para>
- <para>
- You can specify the database table name independently from the class name by
- declaring the table name with the <varname>$_name</varname> class property in each
- of your table classes.
- </para>
- <para>
- <classname>Zend_Db_Table_Abstract</classname> performs no inflection to map the
- class name to the table name. If you omit the declaration of
- <varname>$_name</varname> in your table class, the class maps to a database table
- that matches the spelling of the class name exactly.
- </para>
- <para>
- It is inappropriate to transform identifiers from the database, because this can
- lead to ambiguity or make some identifiers inaccessible. Using the
- <acronym>SQL</acronym> identifiers exactly as they appear in the database makes
- <classname>Zend_Db_Table_Abstract</classname> both simpler and more flexible.
- </para>
- <para>
- If you prefer to use inflection, then you must implement the transformation
- yourself, by overriding the <methodname>_setupTableName()</methodname> method in
- your Table classes. One way to do this is to define an abstract class that extends
- <classname>Zend_Db_Table_Abstract</classname>, and then the rest of your tables
- extend your new abstract class.
- </para>
- <example id="zend.db.table.extending.inflection.example">
- <title>Example of an abstract table class that implements inflection</title>
- <programlisting language="php"><![CDATA[
- abstract class MyAbstractTable extends Zend_Db_Table_Abstract
- {
- protected function _setupTableName()
- {
- if (!$this->_name) {
- $this->_name = myCustomInflector(get_class($this));
- }
- parent::_setupTableName();
- }
- }
- class BugsProducts extends MyAbstractTable
- {
- }
- ]]></programlisting>
- </example>
- <para>
- You are responsible for writing the functions to perform inflection transformation.
- Zend Framework does not provide such a function.
- </para>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|