<?xml version="1.0" encoding="UTF-8"?>
    <!-- EN-Revision: 24249 -->
    <!-- Reviewed: no -->
<sect1 id="zend.db.table.row">

    <title>Zend_Db_Table_Row</title>

    <sect2 id="zend.db.table.row.introduction">

        <title>Introducción</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
                <xref linkend="zend.db.table.rowset"/> . </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 <xref linkend="zend.db.table.relationships"/> 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 createRow() 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 PHP'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. <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>
            </para>

        </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 <methodname>INSERT</methodname> ,
                    <methodname>UPDATE</methodname> , and
                    <methodname>DELETE</methodname> . 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 <xref
                    linkend="zend.db.table.extending.inflection"/> 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>
