Zend_Db_Table_Row is a class that contains an individual row of a Zend_Db_Table object. When you run a query against a Table class, the result is returned in a set of Zend_Db_Table_Row objects. You can also use this object to create new rows and add them to the database table.
Zend_Db_Table_Row is an implementation of the Row Data Gateway pattern.
Zend_Db_Table_Abstract provides methods find()
and
fetchAll()
, which each return an object of type
Zend_Db_Table_Rowset, and the method fetchRow()
,
which returns an object of type Zend_Db_Table_Row.
Example 9.29. Example of fetching a row
<?php $bugs = new Bugs(); $row = $bugs->fetchRow('bug_id = 1'); ?>
A Zend_Db_Table_Rowset object contains a collection of Zend_Db_Table_Row objects. See Section 9.6, “Zend_Db_Table_Rowset”.
Example 9.30. Example of reading a row in a rowset
<?php $bugs = new Bugs(); $rowset = $bugs->fetchAll("bug_status = 'NEW'"); $row = $rowset->current(); ?>
Zend_Db_Table_Row_Abstract provides accessor methods so you can reference columns in the row as object properties.
Example 9.31. Example of reading a column in a row
<?php $bugs = new Bugs(); $row = $bugs->fetchRow('bug_id = 1'); // Echo the value of the bug_description column echo $row->bug_description; ?>
Note | |
---|---|
Earlier versions of Zend_Db_Table_Row mapped these column accessors to the database column names using a string transformation called inflection. Current usage of Zend_Db_Table_Row does not implement inflection. The column accessor you use must match the spelling of the column name as it appears in your database. |
You can access the row's data as an array using the
toArray()
method of the Row object.
This returns an associative array of the colum names
to the column values.
Example 9.32. Example of using the toArray() method
<?php $bugs = new Bugs(); $row = $bugs->fetchRow('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"; } ?>
The array returned from toArray()
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.
The Zend_Db_Table_Row_Abstract class provides methods for fetching rows and rowsets from related tables. See Section 9.7, “Zend_Db_Table Relationships” for more information on table relationships.
You can set individual columns using column accessors, similarly to reading columns as object properties.
This changes the column value of the row as it exists
in your application, but it does not commit the change
to the database yet. You can do that with the
save()
method.
Example 9.33. Example of changing a column in a row
<?php $bugs = new Bugs(); $row = $bugs->fetchRow('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(); ?>
Note | |
---|---|
Currently Zend_Db_Table_Row_Abstract throws an exception if you try to set the value of the primary key column(s) in the row. This is intended to change in Zend Framework 1.0. The Row class should permit the primary key columns to be set, to support sequences and natural primary keys. |
You can create a new row for a given table with the
createRow()
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 save()
method.
Example 9.34. Example of creating a new row for a table
<?php $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(); ?>
The optional argument to the createRow() method is an associative array, with which you can populate fields of the new row.
Example 9.35. Example of populating a new row for a table
<?php $data = array( 'bug_description' => '...description...', 'bug_status' => 'NEW' ); $bugs = new Bugs(); $newRow = $bugs->createRow($data); // INSERT the new row to the database $newRow->save(); ?>
Note | |
---|---|
The |
Zend_Db_Table_Row_Abstract provides the
setFromArray()
method to enable you to set several
columns at once, specified in an associative array
mapping column names to values.
You may find this method convenient for setting values
both for new rows and for rows you need to update.
Example 9.36. Example of using setFromArray() to set values in a new Row
<?php $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(); ?>
You can call the delete()
method on a Row
object. This deletes rows in the database matching the
primary key in the Row object.
Example 9.37. Example of deleting a row
<?php $bugs = new Bugs(); $row = $bugs->fetchRow('bug_id = 1'); // DELETE this row $row->delete(); ?>
You do not have to call save()
to apply
the delete; it is executed against the database immediately.
It is often convenient to save the contents of a database row to be used later. Serialization is the name for the operation to convert an object into a form that is easy to save in offline storage (for example, a file). Objects of type Zend_Db_Table_Row_Abstract are serializable.
Simply use PHP's serialize()
function to
create a string containing a byte-stream representation
of the Row object argument.
Use PHP's unserialize()
function to
restore a string containing a byte-stream representation
of an object. The function returns the original object.
Note that the Row object returned is in a disconnected 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).
Example 9.39. Example of unserializing a serialized row
<?php $rowClone = unserialize($serializedRow); // Now you can use object properties, but read-only echo $rowClone->bug_description; ?>
Why do Rows unserialize in a disconnected state? | |
---|---|
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. |
You can reactivate a disconnected Row, using the
setTable()
method. The argument to this
method is a valid object of type Zend_Db_Table_Abstract,
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.
Example 9.40. Example of reactivating a row
<?php $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(); ?>
You can use an alternative concrete class for instances of Row
by extending Zend_Db_Table_Row_Abstract. Specify the custom
Row class by name either in the $_rowClass
protected member of a Table class, or in the array argument of the
constructor of a Table object.
Example 9.41. Specifying a custom Row class
<?php 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')); ?>
The Row class calls protected methods _insert()
,
_update()
, and _delete()
before
performing the corresponding operations INSERT
,
UPDATE
, and DELETE
. You can add
logic to these methods in your custom Row subclass.
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 belongs
in the insert()
, update()
and
delete()
methods of your Table class.
However, sometimes is may be necessary to do custom logic
in the Row class.
Below are some example cases where it might make sense to implement custom logic in a Row class instead of in the Table class:
Example 9.42. Example of custom logic in a Row class
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.
You need data operations on this table to record the operation to a Zend_Log object, but only if the application configuration has enabled this behavior.
<?php 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(); } ?>
Example 9.43. Example of a Row class that logs insert data for multiple tables
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.
In this example, the logging code is identical in all table classes.
<?php 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'; } ?>
Some people prefer that the table class name match a table name in the RDBMS by using a string transformation called inflection.
Zend_Db classes do not implement inflection by default. See Section 9.4.12.4, “Define Inflection in Zend_Db_Table” for an explanation of this policy.
If you prefer to use inflection, then you must implement
the transformation yourself, by overriding the
_transformColumn()
method in a custom Row class,
and using that custom Row class when you perform queries
against your Table class.
Example 9.44. Example of defining an inflection transformation
This allows you to use a inflected version of the column
name in the accessors. The Row class uses the
_transformColumn()
method to change the name
you use to the native column name in the database table.
<?php class MyInflectedRow extends Zend_Db_Table_Row_Abstract { protected function _transformColumn($key) { $nativeKey = myCustomInflector($key); return $nativeKey; } } 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'; ?>
You are responsible for writing the functions to perform inflection transformation. Zend Framework does not provide such a function.