| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.db.table.row">
- <title>Zend_Db_Table_Row</title>
- <sect2 id="zend.db.table.row.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Db_Table_Row</classname> is a class that contains an individual row of a
- <classname>Zend_Db_Table</classname> object. When you run a query against a Table class,
- the result is returned in a set of <classname>Zend_Db_Table_Row</classname> objects. You
- can also use this object to create new rows and add them to the database table.
- </para>
- <para>
- <classname>Zend_Db_Table_Row</classname> is an implementation of the <ulink
- url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data
- Gateway</ulink> pattern.
- </para>
- </sect2>
- <sect2 id="zend.db.table.row.read">
- <title>Fetching a Row</title>
- <para>
- <classname>Zend_Db_Table_Abstract</classname> provides methods
- <methodname>find()</methodname> and <methodname>fetchAll()</methodname>, which each
- return an object of type <classname>Zend_Db_Table_Rowset</classname>, and the method
- <methodname>fetchRow()</methodname>, which returns an object of type
- <classname>Zend_Db_Table_Row</classname>.
- </para>
- <example id="zend.db.table.row.read.example">
- <title>Example of fetching a row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
- ]]></programlisting>
- </example>
- <para>
- A <classname>Zend_Db_Table_Rowset</classname> object contains a collection of
- <classname>Zend_Db_Table_Row</classname> objects. See the chapter about <link
- linkend="zend.db.table.rowset">table rowset</link> for details.
- </para>
- <example id="zend.db.table.row.read.example-rowset">
- <title>Example of reading a row in a rowset</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $rowset = $bugs->fetchAll($bugs->select()->where('bug_status = ?', 1));
- $row = $rowset->current();
- ]]></programlisting>
- </example>
- <sect3 id="zend.db.table.row.read.get">
- <title>Reading column values from a row</title>
- <para>
- <classname>Zend_Db_Table_Row_Abstract</classname> provides accessor methods so you
- can reference columns in the row as object properties.
- </para>
- <example id="zend.db.table.row.read.get.example">
- <title>Example of reading a column in a row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
- // Echo the value of the bug_description column
- echo $row->bug_description;
- ]]></programlisting>
- </example>
- <note>
- <para>
- Earlier versions of <classname>Zend_Db_Table_Row</classname> mapped these column
- accessors to the database column names using a string transformation called
- <emphasis>inflection</emphasis>.
- </para>
- <para>
- Currently, <classname>Zend_Db_Table_Row</classname> does not implement
- inflection. Accessed property names need to match the spelling of the column
- names as they appear in your database.
- </para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.read.to-array">
- <title>Retrieving Row Data as an Array</title>
- <para>
- You can access the row's data as an array using the
- <methodname>toArray()</methodname> method of the Row object. This returns an
- associative array of the column names to the column values.
- </para>
- <example id="zend.db.table.row.read.to-array.example">
- <title>Example of using the toArray() method</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
- // Get the column/value associative array from the Row object
- $rowArray = $row->toArray();
- // Now use it as a normal array
- foreach ($rowArray as $column => $value) {
- echo "Column: $column\n";
- echo "Value: $value\n";
- }
- ]]></programlisting>
- </example>
- <para>
- The array returned from <methodname>toArray()</methodname> is not updateable. You
- can modify values in the array as you can with any array, but you cannot save
- changes to this array to the database directly.
- </para>
- </sect3>
- <sect3 id="zend.db.table.row.read.relationships">
- <title>Fetching data from related tables</title>
- <para>
- The <classname>Zend_Db_Table_Row_Abstract</classname> class provides methods for
- fetching rows and rowsets from related tables. See the <link
- linkend="zend.db.table.relationships">relationship chapter</link> for more
- information on table relationships.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.write">
- <title>Writing rows to the database</title>
- <sect3 id="zend.db.table.row.write.set">
- <title>Changing column values in a row</title>
- <para>
- You can set individual column values using column accessors, similar to how the
- columns are read as object properties in the example above.
- </para>
- <para>
- Using a column accessor to set a value changes the column value of the row object
- in your application, but it does not commit the change to the database yet. You can
- do that with the <methodname>save()</methodname> method.
- </para>
- <example id="zend.db.table.row.write.set.example">
- <title>Example of changing a column in a row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
- // Change the value of one or more columns
- $row->bug_status = 'FIXED';
- // UPDATE the row in the database with new values
- $row->save();
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.write.insert">
- <title>Inserting a new row</title>
- <para>
- You can create a new row for a given table with the
- <methodname>createRow()</methodname> method of the table class. You can access
- fields of this row with the object-oriented interface, but the row is not stored in
- the database until you call the <methodname>save()</methodname> method.
- </para>
- <example id="zend.db.table.row.write.insert.example">
- <title>Example of creating a new row for a table</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $newRow = $bugs->createRow();
- // Set column values as appropriate for your application
- $newRow->bug_description = '...description...';
- $newRow->bug_status = 'NEW';
- // INSERT the new row to the database
- $newRow->save();
- ]]></programlisting>
- </example>
- <para>
- The optional argument to the <methodname>createRow()</methodname> method is an
- associative array, with which you can populate fields of the new row.
- </para>
- <example id="zend.db.table.row.write.insert.example2">
- <title>Example of populating a new row for a table</title>
- <programlisting language="php"><![CDATA[
- $data = array(
- 'bug_description' => '...description...',
- 'bug_status' => 'NEW'
- );
- $bugs = new Bugs();
- $newRow = $bugs->createRow($data);
- // INSERT the new row to the database
- $newRow->save();
- ]]></programlisting>
- </example>
- <note>
- <para>
- The <methodname>createRow()</methodname> method was called
- <methodname>fetchNew()</methodname> in earlier releases of
- <classname>Zend_Db_Table</classname>. You are encouraged to use the new method
- name, even though the old name continues to work for the sake of backward
- compatibility.
- </para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.write.set-from-array">
- <title>Changing values in multiple columns</title>
- <para>
- <classname>Zend_Db_Table_Row_Abstract</classname> provides the
- <methodname>setFromArray()</methodname> method to enable you to set several columns
- in a single row at once, specified in an associative array that maps the column
- names to values. You may find this method convenient for setting values both for new
- rows and for rows you need to update.
- </para>
- <example id="zend.db.table.row.write.set-from-array.example">
- <title>Example of using setFromArray() to set values in a new Row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $newRow = $bugs->createRow();
- // Data are arranged in an associative array
- $data = array(
- 'bug_description' => '...description...',
- 'bug_status' => 'NEW'
- );
- // Set all the column values at once
- $newRow->setFromArray($data);
- // INSERT the new row to the database
- $newRow->save();
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.write.delete">
- <title>Deleting a row</title>
- <para>
- You can call the <methodname>delete()</methodname> method on a Row object. This
- deletes rows in the database matching the primary key in the Row object.
- </para>
- <example id="zend.db.table.row.write.delete.example">
- <title>Example of deleting a row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow('bug_id = 1');
- // DELETE this row
- $row->delete();
- ]]></programlisting>
- </example>
- <para>
- You do not have to call <methodname>save()</methodname> to apply the delete; it is
- executed against the database immediately.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.serialize">
- <title>Serializing and unserializing rows</title>
- <para>
- It is often convenient to save the contents of a database row to be used later.
- <emphasis>Serialization</emphasis> is the name for the operation that converts an
- object into a form that is easy to save in offline storage (for example, a file).
- Objects of type <classname>Zend_Db_Table_Row_Abstract</classname> are serializable.
- </para>
- <sect3 id="zend.db.table.row.serialize.serializing">
- <title>Serializing a Row</title>
- <para>
- Simply use <acronym>PHP</acronym>'s <methodname>serialize()</methodname> function to
- create a string containing a byte-stream representation of the Row object argument.
- </para>
- <example id="zend.db.table.row.serialize.serializing.example">
- <title>Example of serializing a row</title>
- <programlisting language="php"><![CDATA[
- $bugs = new Bugs();
- $row = $bugs->fetchRow('bug_id = 1');
- // Convert object to serialized form
- $serializedRow = serialize($row);
- // Now you can write $serializedRow to a file, etc.
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.serialize.unserializing">
- <title>Unserializing Row Data</title>
- <para>
- Use <acronym>PHP</acronym>'s <methodname>unserialize()</methodname> function to
- restore a string containing a byte-stream representation of an object. The function
- returns the original object.
- </para>
- <para>
- Note that the Row object returned is in a <emphasis>disconnected</emphasis> state.
- You can read the Row object and its properties, but you cannot change values in the
- Row or execute other methods that require a database connection (for example,
- queries against related tables).
- </para>
- <example id="zend.db.table.row.serialize.unserializing.example">
- <title>Example of unserializing a serialized row</title>
- <programlisting language="php"><![CDATA[
- $rowClone = unserialize($serializedRow);
- // Now you can use object properties, but read-only
- echo $rowClone->bug_description;
- ]]></programlisting>
- </example>
- <note>
- <title>Why do Rows unserialize in a disconnected state?</title>
- <para>
- A serialized object is a string that is readable to anyone who possesses it. It
- could be a security risk to store parameters such as database account and
- password in plain, unencrypted text in the serialized string. You would not
- want to store such data to a text file that is not protected, or send it in an
- email or other medium that is easily read by potential attackers. The reader of
- the serialized object should not be able to use it to gain access to your
- database without knowing valid credentials.
- </para>
- </note>
- </sect3>
- <sect3 id="zend.db.table.row.serialize.set-table">
- <title>Reactivating a Row as Live Data</title>
- <para>
- You can reactivate a disconnected Row, using the <methodname>setTable()</methodname>
- method. The argument to this method is a valid object of type
- <classname>Zend_Db_Table_Abstract</classname>, which you create. Creating a Table
- object requires a live connection to the database, so by reassociating the Table
- with the Row, the Row gains access to the database. Subsequently, you can change
- values in the Row object and save the changes to the database.
- </para>
- <example id="zend.db.table.row.serialize.set-table.example">
- <title>Example of reactivating a row</title>
- <programlisting language="php"><![CDATA[
- $rowClone = unserialize($serializedRow);
- $bugs = new Bugs();
- // Reconnect the row to a table, and
- // thus to a live database connection
- $rowClone->setTable($bugs);
- // Now you can make changes to the row and save them
- $rowClone->bug_status = 'FIXED';
- $rowClone->save();
- ]]></programlisting>
- </example>
- </sect3>
- </sect2>
- <sect2 id="zend.db.table.row.extending">
- <title>Extending the Row class</title>
- <para>
- <classname>Zend_Db_Table_Row</classname> is the default concrete class that extends
- <classname>Zend_Db_Table_Row_Abstract</classname>. You can define your own concrete
- class for instances of Row by extending
- <classname>Zend_Db_Table_Row_Abstract</classname>. To use your new Row class to store
- results of Table queries, specify the custom Row class by name either in the
- <varname>$_rowClass</varname> protected member of a Table class, or in the array
- argument of the constructor of a Table object.
- </para>
- <example id="zend.db.table.row.extending.example">
- <title>Specifying a custom Row class</title>
- <programlisting language="php"><![CDATA[
- class MyRow extends Zend_Db_Table_Row_Abstract
- {
- // ...customizations
- }
- // Specify a custom Row to be used by default
- // in all instances of a Table class.
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_rowClass = 'MyRow';
- }
- // Or specify a custom Row to be used in one
- // instance of a Table class.
- $bugs = new Bugs(array('rowClass' => 'MyRow'));
- ]]></programlisting>
- </example>
- <sect3 id="zend.db.table.row.extending.overriding">
- <title>Row initialization</title>
- <para>
- If application-specific logic needs to be initialized when a row is constructed,
- you can select to move your tasks to the <methodname>init()</methodname> method,
- which is called after all row 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.row.init.usage.example">
- <title>Example usage of init() method</title>
- <programlisting language="php"><![CDATA[
- class MyApplicationRow extends Zend_Db_Table_Row_Abstract
- {
- protected $_role;
- public function init()
- {
- $this->_role = new MyRoleClass();
- }
- }
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.extending.insert-update">
- <title>Defining Custom Logic for Insert, Update, and Delete in Zend_Db_Table_Row</title>
- <para>
- The Row class calls protected methods <methodname>_insert()</methodname>,
- <methodname>_update()</methodname>, and <methodname>_delete()</methodname> before
- performing the corresponding operations <constant>INSERT</constant>,
- <constant>UPDATE</constant>, and <constant>DELETE</constant>. You can add logic to
- these methods in your custom Row subclass.
- </para>
- <para>
- If you need to do custom logic in a specific table, and the custom logic must occur
- for every operation on that table, it may make more sense to implement your custom
- code in the <methodname>insert()</methodname>, <methodname>update()</methodname> and
- <methodname>delete()</methodname> methods of your Table class. However, sometimes it
- may be necessary to do custom logic in the Row class.
- </para>
- <para>
- Below are some example cases where it might make sense to implement custom logic in
- a Row class instead of in the Table class:
- </para>
- <example id="zend.db.table.row.extending.overriding-example1">
- <title>Example of custom logic in a Row class</title>
- <para>
- The custom logic may not apply in all cases of operations on the respective
- Table. You can provide custom logic on demand by implementing it in a Row class
- and creating an instance of the Table class with that custom Row class
- specified. Otherwise, the Table uses the default Row class.
- </para>
- <para>
- You need data operations on this table to record the operation to a
- <classname>Zend_Log</classname> object, but only if the application
- configuration has enabled this behavior.
- </para>
- <programlisting language="php"><![CDATA[
- class MyLoggingRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _insert()
- {
- $log = Zend_Registry::get('database_log');
- $log->info(Zend_Debug::dump($this->_data,
- "INSERT: $this->_tableClass",
- false)
- );
- }
- }
- // $loggingEnabled is an example property that depends
- // on your application configuration
- if ($loggingEnabled) {
- $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
- } else {
- $bugs = new Bugs();
- }
- ]]></programlisting>
- </example>
- <example id="zend.db.table.row.extending.overriding-example2">
- <title>Example of a Row class that logs insert data for multiple tables</title>
- <para>
- The custom logic may be common to multiple tables. Instead of implementing the
- same custom logic in every one of your Table classes, you can implement the
- code for such actions in the definition of a Row class, and use this Row in
- each of your Table classes.
- </para>
- <para>
- In this example, the logging code is identical in all table classes.
- </para>
- <programlisting language="php"><![CDATA[
- class MyLoggingRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _insert()
- {
- $log = Zend_Registry::get('database_log');
- $log->info(Zend_Debug::dump($this->_data,
- "INSERT: $this->_tableClass",
- false)
- );
- }
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_rowClass = 'MyLoggingRow';
- }
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_rowClass = 'MyLoggingRow';
- }
- ]]></programlisting>
- </example>
- </sect3>
- <sect3 id="zend.db.table.row.extending.inflection">
- <title>Define Inflection in Zend_Db_Table_Row</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>
- <classname>Zend_Db</classname> classes do not implement inflection by default. See
- the chapter about <link linkend="zend.db.table.extending.inflection">extending
- inflection</link> for an explanation of this policy.
- </para>
- <para>
- If you prefer to use inflection, then you must implement the transformation
- yourself, by overriding the <methodname>_transformColumn()</methodname> method in a
- custom Row class, and using that custom Row class when you perform queries against
- your Table class.
- </para>
- <example id="zend.db.table.row.extending.inflection.example">
- <title>Example of defining an inflection transformation</title>
- <para>
- This allows you to use an inflected version of the column name in the
- accessors. The Row class uses the <methodname>_transformColumn()</methodname>
- method to change the name you use to the native column name in the database
- table.
- </para>
- <programlisting language="php"><![CDATA[
- class MyInflectedRow extends Zend_Db_Table_Row_Abstract
- {
- protected function _transformColumn($columnName)
- {
- $nativeColumnName = myCustomInflector($columnName);
- return $nativeColumnName;
- }
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_rowClass = 'MyInflectedRow';
- }
- $bugs = new Bugs();
- $row = $bugs->fetchNew();
- // Use camelcase column names, and rely on the
- // transformation function to change it into the
- // native representation.
- $row->bugDescription = 'New description';
- ]]></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:
- -->
|