1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 20766 -->
4 <sect1 id="zend.db.table.row">
6 <title>Zend_Db_Table_Row</title>
8 <sect2 id="zend.db.table.row.introduction">
10 <title>Introducción</title>
13 <classname>Zend_Db_Table_Row</classname> is a class that contains an
14 individual row of a <classname>Zend_Db_Table</classname> object.
15 When you run a query against a Table class, the result is returned
16 in a set of <classname>Zend_Db_Table_Row</classname> objects. You
17 can also use this object to create new rows and add them to the
18 database table. </para>
21 <classname>Zend_Db_Table_Row</classname> is an implementation of the
23 url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html"
24 >Row Data Gateway</ulink> pattern. </para>
28 <sect2 id="zend.db.table.row.read">
30 <title>Fetching a Row</title>
33 <classname>Zend_Db_Table_Abstract</classname> provides methods
34 <methodname>find()</methodname> and
35 <methodname>fetchAll()</methodname> , which each return an
36 object of type <classname>Zend_Db_Table_Rowset</classname> , and the
37 method <methodname>fetchRow()</methodname> , which returns an object
38 of type <classname>Zend_Db_Table_Row</classname> . </para>
40 <example id="zend.db.table.row.read.example">
42 <title>Example of fetching a row</title>
44 <programlisting language="php"><![CDATA[
46 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
51 <para> A <classname>Zend_Db_Table_Rowset</classname> object contains a
52 collection of <classname>Zend_Db_Table_Row</classname> objects. See
53 <xref linkend="zend.db.table.rowset"/> . </para>
55 <example id="zend.db.table.row.read.example-rowset">
57 <title>Example of reading a row in a rowset</title>
59 <programlisting language="php"><![CDATA[
61 $rowset = $bugs->fetchAll($bugs->select()->where('bug_status = ?', 1));
62 $row = $rowset->current();
67 <sect3 id="zend.db.table.row.read.get">
69 <title>Reading column values from a row</title>
72 <classname>Zend_Db_Table_Row_Abstract</classname> provides
73 accessor methods so you can reference columns in the row as
74 object properties. </para>
76 <example id="zend.db.table.row.read.get.example">
78 <title>Example of reading a column in a row</title>
80 <programlisting language="php"><![CDATA[
82 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
84 // Echo the value of the bug_description column
85 echo $row->bug_description;
92 <para> Earlier versions of
93 <classname>Zend_Db_Table_Row</classname> mapped these
94 column accessors to the database column names using a string
95 transformation called <emphasis>inflection</emphasis> . </para>
97 <para> Currently, <classname>Zend_Db_Table_Row</classname> does
98 not implement inflection. Accessed property names need to
99 match the spelling of the column names as they appear in
100 your database. </para>
106 <sect3 id="zend.db.table.row.read.to-array">
108 <title>Retrieving Row Data as an Array</title>
110 <para> You can access the row's data as an array using the
111 <methodname>toArray()</methodname> method of the Row object.
112 This returns an associative array of the column names to the
113 column values. </para>
115 <example id="zend.db.table.row.read.to-array.example">
117 <title>Example of using the toArray() method</title>
119 <programlisting language="php"><![CDATA[
121 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
123 // Get the column/value associative array from the Row object
124 $rowArray = $row->toArray();
126 // Now use it as a normal array
127 foreach ($rowArray as $column => $value) {
128 echo "Column: $column\n";
129 echo "Value: $value\n";
135 <para> The array returned from <methodname>toArray()</methodname> is
136 not updateable. You can modify values in the array as you can
137 with any array, but you cannot save changes to this array to the
138 database directly. </para>
142 <sect3 id="zend.db.table.row.read.relationships">
144 <title>Fetching data from related tables</title>
146 <para> The <classname>Zend_Db_Table_Row_Abstract</classname> class
147 provides methods for fetching rows and rowsets from related
148 tables. See <xref linkend="zend.db.table.relationships"/> for
149 more information on table relationships. </para>
155 <sect2 id="zend.db.table.row.write">
157 <title>Writing rows to the database</title>
159 <sect3 id="zend.db.table.row.write.set">
161 <title>Changing column values in a row</title>
163 <para>You can set individual column values using column accessors,
164 similar to how the columns are read as object properties in the
165 example above.</para>
167 <para> Using a column accessor to set a value changes the column
168 value of the row object in your application, but it does not
169 commit the change to the database yet. You can do that with the
170 <methodname>save()</methodname> method. </para>
172 <example id="zend.db.table.row.write.set.example">
174 <title>Example of changing a column in a row</title>
176 <programlisting language="php"><![CDATA[
178 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
180 // Change the value of one or more columns
181 $row->bug_status = 'FIXED';
183 // UPDATE the row in the database with new values
191 <sect3 id="zend.db.table.row.write.insert">
193 <title>Inserting a new row</title>
195 <para> You can create a new row for a given table with the
196 <methodname>createRow()</methodname> method of the table
197 class. You can access fields of this row with the
198 object-oriented interface, but the row is not stored in the
199 database until you call the <methodname>save()</methodname>
202 <example id="zend.db.table.row.write.insert.example">
204 <title>Example of creating a new row for a table</title>
206 <programlisting language="php"><![CDATA[
208 $newRow = $bugs->createRow();
210 // Set column values as appropriate for your application
211 $newRow->bug_description = '...description...';
212 $newRow->bug_status = 'NEW';
214 // INSERT the new row to the database
220 <para>The optional argument to the createRow() method is an
221 associative array, with which you can populate fields of the new
224 <example id="zend.db.table.row.write.insert.example2">
226 <title>Example of populating a new row for a table</title>
228 <programlisting language="php"><![CDATA[
230 'bug_description' => '...description...',
231 'bug_status' => 'NEW'
235 $newRow = $bugs->createRow($data);
237 // INSERT the new row to the database
245 <para> The <methodname>createRow()</methodname> method was
246 called <methodname>fetchNew()</methodname> in earlier
247 releases of <classname>Zend_Db_Table</classname> . You are
248 encouraged to use the new method name, even though the old
249 name continues to work for the sake of backward
250 compatibility. </para>
256 <sect3 id="zend.db.table.row.write.set-from-array">
258 <title>Changing values in multiple columns</title>
261 <classname>Zend_Db_Table_Row_Abstract</classname> provides the
262 <methodname>setFromArray()</methodname> method to enable you
263 to set several columns in a single row at once, specified in an
264 associative array that maps the column names to values. You may
265 find this method convenient for setting values both for new rows
266 and for rows you need to update. </para>
268 <example id="zend.db.table.row.write.set-from-array.example">
270 <title>Example of using setFromArray() to set values in a new
273 <programlisting language="php"><![CDATA[
275 $newRow = $bugs->createRow();
277 // Data are arranged in an associative array
279 'bug_description' => '...description...',
280 'bug_status' => 'NEW'
283 // Set all the column values at once
284 $newRow->setFromArray($data);
286 // INSERT the new row to the database
294 <sect3 id="zend.db.table.row.write.delete">
296 <title>Deleting a row</title>
298 <para> You can call the <methodname>delete()</methodname> method on
299 a Row object. This deletes rows in the database matching the
300 primary key in the Row object. </para>
302 <example id="zend.db.table.row.write.delete.example">
304 <title>Example of deleting a row</title>
306 <programlisting language="php"><![CDATA[
308 $row = $bugs->fetchRow('bug_id = 1');
316 <para> You do not have to call <methodname>save()</methodname> to
317 apply the delete; it is executed against the database
324 <sect2 id="zend.db.table.row.serialize">
326 <title>Serializing and unserializing rows</title>
328 <para> It is often convenient to save the contents of a database row to
329 be used later. <emphasis>Serialization</emphasis> is the name for
330 the operation that converts an object into a form that is easy to
331 save in offline storage (for example, a file). Objects of type
332 <classname>Zend_Db_Table_Row_Abstract</classname> are
333 serializable. </para>
335 <sect3 id="zend.db.table.row.serialize.serializing">
337 <title>Serializing a Row</title>
339 <para> Simply use <acronym>PHP</acronym> 's
340 <methodname>serialize()</methodname> function to create a
341 string containing a byte-stream representation of the Row object
344 <example id="zend.db.table.row.serialize.serializing.example">
346 <title>Example of serializing a row</title>
348 <programlisting language="php"><![CDATA[
350 $row = $bugs->fetchRow('bug_id = 1');
352 // Convert object to serialized form
353 $serializedRow = serialize($row);
355 // Now you can write $serializedRow to a file, etc.
362 <sect3 id="zend.db.table.row.serialize.unserializing">
364 <title>Unserializing Row Data</title>
366 <para> Use PHP's <methodname>unserialize()</methodname> function to
367 restore a string containing a byte-stream representation of an
368 object. The function returns the original object. </para>
370 <para> Note that the Row object returned is in a
371 <emphasis>disconnected</emphasis> state. You can read the
372 Row object and its properties, but you cannot change values in
373 the Row or execute other methods that require a database
374 connection (for example, queries against related tables). </para>
376 <example id="zend.db.table.row.serialize.unserializing.example">
378 <title>Example of unserializing a serialized row</title>
380 <programlisting language="php"><![CDATA[
381 $rowClone = unserialize($serializedRow);
383 // Now you can use object properties, but read-only
384 echo $rowClone->bug_description;
391 <title>Why do Rows unserialize in a disconnected state?</title>
393 <para>A serialized object is a string that is readable to anyone
394 who possesses it. It could be a security risk to store
395 parameters such as database account and password in plain,
396 unencrypted text in the serialized string. You would not
397 want to store such data to a text file that is not
398 protected, or send it in an email or other medium that is
399 easily read by potential attackers. The reader of the
400 serialized object should not be able to use it to gain
401 access to your database without knowing valid
408 <sect3 id="zend.db.table.row.serialize.set-table">
410 <title>Reactivating a Row as Live Data</title>
412 <para> You can reactivate a disconnected Row, using the
413 <methodname>setTable()</methodname> method. The argument to
414 this method is a valid object of type
415 <classname>Zend_Db_Table_Abstract</classname> , which you
416 create. Creating a Table object requires a live connection to
417 the database, so by reassociating the Table with the Row, the
418 Row gains access to the database. Subsequently, you can change
419 values in the Row object and save the changes to the database. </para>
421 <example id="zend.db.table.row.serialize.set-table.example">
423 <title>Example of reactivating a row</title>
425 <programlisting language="php"><![CDATA[
426 $rowClone = unserialize($serializedRow);
430 // Reconnect the row to a table, and
431 // thus to a live database connection
432 $rowClone->setTable($bugs);
434 // Now you can make changes to the row and save them
435 $rowClone->bug_status = 'FIXED';
445 <sect2 id="zend.db.table.row.extending">
447 <title>Extending the Row class</title>
450 <classname>Zend_Db_Table_Row</classname> is the default concrete
451 class that extends <classname>Zend_Db_Table_Row_Abstract</classname>
452 . You can define your own concrete class for instances of Row by
453 extending <classname>Zend_Db_Table_Row_Abstract</classname> . To use
454 your new Row class to store results of Table queries, specify the
455 custom Row class by name either in the <varname>$_rowClass</varname>
456 protected member of a Table class, or in the array argument of the
457 constructor of a Table object. </para>
459 <example id="zend.db.table.row.extending.example">
461 <title>Specifying a custom Row class</title>
463 <programlisting language="php"><![CDATA[
464 class MyRow extends Zend_Db_Table_Row_Abstract
469 // Specify a custom Row to be used by default
470 // in all instances of a Table class.
471 class Products extends Zend_Db_Table_Abstract
473 protected $_name = 'products';
474 protected $_rowClass = 'MyRow';
477 // Or specify a custom Row to be used in one
478 // instance of a Table class.
479 $bugs = new Bugs(array('rowClass' => 'MyRow'));
484 <sect3 id="zend.db.table.row.extending.overriding">
486 <title>Row initialization</title>
488 <para> If application-specific logic needs to be initialized when a
489 row is constructed, you can select to move your tasks to the
490 <methodname>init()</methodname> method, which is called
491 after all row metadata has been processed. This is recommended
492 over the <methodname>__construct</methodname> method if you do
493 not need to alter the metadata in any programmatic way. <example
494 id="zend.db.table.row.init.usage.example">
496 <title>Example usage of init() method</title>
498 <programlisting language="php"><![CDATA[
499 class MyApplicationRow extends Zend_Db_Table_Row_Abstract
503 public function init()
505 $this->_role = new MyRoleClass();
515 <sect3 id="zend.db.table.row.extending.insert-update">
517 <title>Defining Custom Logic for Insert, Update, and Delete in
518 Zend_Db_Table_Row</title>
520 <para> The Row class calls protected methods
521 <methodname>_insert()</methodname> ,
522 <methodname>_update()</methodname> , and
523 <methodname>_delete()</methodname> before performing the
524 corresponding operations <methodname>INSERT</methodname> ,
525 <methodname>UPDATE</methodname> , and
526 <methodname>DELETE</methodname> . You can add logic to these
527 methods in your custom Row subclass. </para>
529 <para> If you need to do custom logic in a specific table, and the
530 custom logic must occur for every operation on that table, it
531 may make more sense to implement your custom code in the
532 <methodname>insert()</methodname> ,
533 <methodname>update()</methodname> and
534 <methodname>delete()</methodname> methods of your Table
535 class. However, sometimes it may be necessary to do custom logic
536 in the Row class. </para>
538 <para>Below are some example cases where it might make sense to
539 implement custom logic in a Row class instead of in the Table
542 <example id="zend.db.table.row.extending.overriding-example1">
544 <title>Example of custom logic in a Row class</title>
546 <para>The custom logic may not apply in all cases of operations
547 on the respective Table. You can provide custom logic on
548 demand by implementing it in a Row class and creating an
549 instance of the Table class with that custom Row class
550 specified. Otherwise, the Table uses the default Row
553 <para> You need data operations on this table to record the
554 operation to a <classname>Zend_Log</classname> object, but
555 only if the application configuration has enabled this
558 <programlisting language="php"><![CDATA[
559 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
561 protected function _insert()
563 $log = Zend_Registry::get('database_log');
564 $log->info(Zend_Debug::dump($this->_data,
565 "INSERT: $this->_tableClass",
571 // $loggingEnabled is an example property that depends
572 // on your application configuration
573 if ($loggingEnabled) {
574 $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
582 <example id="zend.db.table.row.extending.overriding-example2">
584 <title>Example of a Row class that logs insert data for multiple
587 <para>The custom logic may be common to multiple tables. Instead
588 of implementing the same custom logic in every one of your
589 Table classes, you can implement the code for such actions
590 in the definition of a Row class, and use this Row in each
591 of your Table classes.</para>
593 <para>In this example, the logging code is identical in all
594 table classes.</para>
596 <programlisting language="php"><![CDATA[
597 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
599 protected function _insert()
601 $log = Zend_Registry::get('database_log');
602 $log->info(Zend_Debug::dump($this->_data,
603 "INSERT: $this->_tableClass",
609 class Bugs extends Zend_Db_Table_Abstract
611 protected $_name = 'bugs';
612 protected $_rowClass = 'MyLoggingRow';
615 class Products extends Zend_Db_Table_Abstract
617 protected $_name = 'products';
618 protected $_rowClass = 'MyLoggingRow';
626 <sect3 id="zend.db.table.row.extending.inflection">
628 <title>Define Inflection in Zend_Db_Table_Row</title>
630 <para> Some people prefer that the table class name match a table
631 name in the <acronym>RDBMS</acronym> by using a string
632 transformation called <emphasis>inflection</emphasis> . </para>
635 <classname>Zend_Db</classname> classes do not implement
636 inflection by default. See <xref
637 linkend="zend.db.table.extending.inflection"/> for an
638 explanation of this policy. </para>
640 <para> If you prefer to use inflection, then you must implement the
641 transformation yourself, by overriding the
642 <methodname>_transformColumn()</methodname> method in a
643 custom Row class, and using that custom Row class when you
644 perform queries against your Table class. </para>
646 <example id="zend.db.table.row.extending.inflection.example">
648 <title>Example of defining an inflection transformation</title>
650 <para> This allows you to use an inflected version of the column
651 name in the accessors. The Row class uses the
652 <methodname>_transformColumn()</methodname> method to
653 change the name you use to the native column name in the
654 database table. </para>
656 <programlisting language="php"><![CDATA[
657 class MyInflectedRow extends Zend_Db_Table_Row_Abstract
659 protected function _transformColumn($columnName)
661 $nativeColumnName = myCustomInflector($columnName);
662 return $nativeColumnName;
666 class Bugs extends Zend_Db_Table_Abstract
668 protected $_name = 'bugs';
669 protected $_rowClass = 'MyInflectedRow';
673 $row = $bugs->fetchNew();
675 // Use camelcase column names, and rely on the
676 // transformation function to change it into the
677 // native representation.
678 $row->bugDescription = 'New description';
683 <para>You are responsible for writing the functions to perform
684 inflection transformation. Zend Framework does not provide such