TigerZF
🌐Español

27.7. Zend_Db_Table_Rowset

27.7.1. Introducción

Cuando ejecuta una consulta contra una clase Table usando los métodos find() o fetchAll(), el resultado se devuelve en un objeto de tipo Zend_Db_Table_Rowset_Abstract. Un Rowset contiene una colección de objetos que descienden de Zend_Db_Table_Row_Abstract. Puede iterar a través del Rowset y acceder a objetos Row individuales, leyendo o modificando datos en las Rows.

27.7.2. Obtener un Rowset

Zend_Db_Table_Abstract proporciona los métodos find() y fetchAll(), cada uno de los cuales devuelve un objeto de tipo Zend_Db_Table_Rowset_Abstract.

Ejemplo 27.134. Ejemplo de obtención de un rowset

$bugs   = new Bugs();
$rowset = $bugs->fetchAll("bug_status = 'NEW'");

27.7.3. Recuperar Rows de un Rowset

El Rowset en sí es normalmente menos interesante que las Rows que contiene. Esta sección ilustra cómo obtener las Rows que componen el Rowset.

Una consulta legítima devuelve cero filas cuando ninguna fila de la base de datos coincide con las condiciones de la consulta. Por lo tanto, un objeto Rowset podría contener cero objetos Row. Dado que Zend_Db_Table_Rowset_Abstract implementa la interfaz Countable, puede usar count() para determinar el número de Rows en el Rowset.

Ejemplo 27.135. Contar las Rows en un Rowset

$rowset   = $bugs->fetchAll("bug_status = 'FIXED'");

$rowCount = count($rowset);

if ($rowCount > 0) {
    echo "found $rowCount rows";
} else {
    echo 'no rows matched the query';
}

Ejemplo 27.136. Leer una única Row de un Rowset

La forma más simple de acceder a una Row de un Rowset es usar el método current(). Esto es particularmente apropiado cuando el Rowset contiene exactamente una Row.

$bugs   = new Bugs();
$rowset = $bugs->fetchAll("bug_id = 1");
$row    = $rowset->current();

Si el Rowset contiene cero filas, current() devuelve el valor NULL de PHP.

Ejemplo 27.137. Iterar a través de un Rowset

Los objetos que descienden de Zend_Db_Table_Rowset_Abstract implementan la interfaz SeekableIterator, lo que significa que puede recorrerlos usando la construcción foreach(). Cada valor que recupera de esta manera es un objeto Zend_Db_Table_Row_Abstract que corresponde a un registro de la tabla.

$bugs = new Bugs();

// fetch all records from the table
$rowset = $bugs->fetchAll();

foreach ($rowset as $row) {

    // output 'Zend_Db_Table_Row' or similar
    echo get_class($row) . "\n";

    // read a column in the row
    $status = $row->bug_status;

    // modify a column in the current row
    $row->assigned_to = 'mmouse';

    // write the change to the database
    $row->save();
}

Ejemplo 27.138. Desplazarse a una posición conocida dentro de un Rowset

SeekableIterator le permite desplazarse a una posición a la que le gustaría que el iterador salte. Simplemente use el método seek() para eso. Páselo un entero que represente el número de la Row a la que le gustaría que su Rowset apunte a continuación; no olvide que empieza con el índice 0. Si el índice es incorrecto, es decir, no existe, se lanzará una excepción. Debe usar count() para comprobar el número de resultados antes de desplazarse a una posición.

$bugs = new Bugs();

// fetch all records from the table
$rowset = $bugs->fetchAll();

// takes the iterator to the 9th element (zero is one element) :
$rowset->seek(8);

// retrieve it
$row9 = $rowset->current();

// and use it
$row9->assigned_to = 'mmouse';
$row9->save();

getRow() le permite obtener una Row específica en el Rowset, conociendo su posición; no olvide, sin embargo, que las posiciones empiezan con el índice cero. El primer parámetro de getRow() es un entero para la posición solicitada. El segundo parámetro opcional es un booleano; indica al iterador del Rowset si debe desplazarse a esa posición al mismo tiempo o no (el valor predeterminado es FALSE). Este método devuelve un objeto Zend_Db_Table_Row por defecto. Si la posición solicitada no existe, se lanzará una excepción. He aquí un ejemplo:

$bugs = new Bugs();

// fetch all records from the table
$rowset = $bugs->fetchAll();

// retrieve the 9th element immediately:
$row9 = $rowset->getRow(8);

// and use it:
$row9->assigned_to = 'mmouse';
$row9->save();

Después de tener acceso a un objeto Row individual, puede manipular la Row usando los métodos descritos en Zend_Db_Table_Row.

27.7.4. Recuperar un Rowset como Array

Puede acceder a todos los datos del Rowset como un array usando el método toArray() del objeto Rowset. Esto devuelve un array que contiene una entrada por Row. Cada entrada es un array asociativo con claves que corresponden a nombres de columna y elementos que corresponden a los respectivos valores de columna.

Ejemplo 27.139. Uso de toArray()

$bugs   = new Bugs();
$rowset = $bugs->fetchAll();

$rowsetArray = $rowset->toArray();

$rowCount = 1;
foreach ($rowsetArray as $rowArray) {
    echo "row #$rowCount:\n";
    foreach ($rowArray as $column => $value) {
        echo "\t$column => $value\n";
    }
    ++$rowCount;
    echo "\n";
}

El array devuelto por toArray() no es actualizable. Es decir, puede modificar valores en el array como con cualquier array, pero los cambios en los datos del array no se propagan a la base de datos.

27.7.5. Serializar y deserializar un Rowset

Los objetos de tipo Zend_Db_Table_Rowset_Abstract son serializables. De manera similar a serializar un objeto Row individual, puede serializar un Rowset y deserializarlo más tarde.

Ejemplo 27.140. Serializar un Rowset

Simplemente use la función serialize() de PHP para crear una cadena que contenga una representación en flujo de bytes del argumento objeto Rowset.

$bugs   = new Bugs();
$rowset = $bugs->fetchAll();

// Convert object to serialized form
$serializedRowset = serialize($rowset);

// Now you can write $serializedRowset to a file, etc.

Ejemplo 27.141. Deserializar un Rowset serializado

Use la función unserialize() de PHP para restaurar una cadena que contenga una representación en flujo de bytes de un objeto. La función devuelve el objeto original.

Tenga en cuenta que el objeto Rowset devuelto está en un estado desconectado. Puede iterar a través del Rowset y leer los objetos Row y sus propiedades, pero no puede cambiar valores en las Rows ni ejecutar otros métodos que requieran una conexión a la base de datos (por ejemplo, consultas contra tablas relacionadas).

$rowsetDisconnected = unserialize($serializedRowset);

// Now you can use object methods and properties, but read-only
$row = $rowsetDisconnected->current();
echo $row->bug_description;

[Note] ¿Por qué los Rowsets se deserializan en un estado desconectado?

Un objeto serializado es una cadena que puede leer cualquiera que la posea. Podría ser un riesgo de seguridad almacenar parámetros como la cuenta y la contraseña de la base de datos en texto plano sin cifrar dentro de la cadena serializada. No querría almacenar dichos datos en un archivo de texto que no esté protegido, ni enviarlos por correo electrónico u otro medio que sea fácilmente legible por posibles atacantes. Quien lea el objeto serializado no debería poder usarlo para obtener acceso a su base de datos sin conocer credenciales válidas.

Puede reactivar un Rowset desconectado usando el método setTable(). El argumento de este método es un objeto válido de tipo Zend_Db_Table_Abstract, que usted crea. Crear un objeto Table requiere una conexión activa a la base de datos, por lo que, al reasociar la Table con el Rowset, el Rowset obtiene acceso a la base de datos. Posteriormente, puede cambiar valores en los objetos Row contenidos en el Rowset y guardar los cambios en la base de datos.

Ejemplo 27.142. Reactivar un Rowset como datos activos

$rowset = unserialize($serializedRowset);

$bugs = new Bugs();

// Reconnect the rowset to a table, and
// thus to a live database connection
$rowset->setTable($bugs);

$row = $rowset->current();

// Now you can make changes to the row and save them
$row->bug_status = 'FIXED';
$row->save();

Reactivar un Rowset con setTable() también reactiva todos los objetos Row contenidos en ese Rowset.

27.7.6. Extender la clase Rowset

Puede usar una clase concreta alternativa para instancias de Rowsets extendiendo Zend_Db_Table_Rowset_Abstract. Especifique la clase Rowset personalizada por nombre, ya sea en el miembro protegido $_rowsetClass de una clase Table, o en el argumento de array del constructor de un objeto Table.

Ejemplo 27.143. Especificar una clase Rowset personalizada

class MyRowset extends Zend_Db_Table_Rowset_Abstract
{
    // ...customizations
}

// Specify a custom Rowset to be used by default
// in all instances of a Table class.
class Products extends Zend_Db_Table_Abstract
{
    protected $_name = 'products';
    protected $_rowsetClass = 'MyRowset';
}

// Or specify a custom Rowset to be used in one
// instance of a Table class.
$bugs = new Bugs(array('rowsetClass' => 'MyRowset'));

Normalmente, la clase concreta estándar Zend_Db_Rowset es suficiente para la mayoría de los usos. Sin embargo, podría resultarle útil añadir nueva lógica a un Rowset, específica para una Table dada. Por ejemplo, un nuevo método podría calcular un agregado sobre todas las Rows en el Rowset.

Ejemplo 27.144. Ejemplo de clase Rowset con un nuevo método

class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract
{
    /**
     * Find the Row in the current Rowset with the
     * greatest value in its 'updated_at' column.
     */
    public function getLatestUpdatedRow()
    {
        $max_updated_at = 0;
        $latestRow = null;
        foreach ($this as $row) {
            if ($row->updated_at > $max_updated_at) {
                $latestRow = $row;
            }
        }
        return $latestRow;
    }
}

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';
    protected $_rowsetClass = 'MyBugsRowset';
}