1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.db.table.rowset">
<title>Zend_Db_Table_Rowset</title>
<sect2 id="zend.db.table.rowset.introduction">
<title>Introduction</title>
<para>
When you run a query against a Table class using the <methodname>find()</methodname> or
<methodname>fetchAll()</methodname> methods, the result is returned in an object of type
<classname>Zend_Db_Table_Rowset_Abstract</classname>. A Rowset contains a collection of
objects descending from <classname>Zend_Db_Table_Row_Abstract</classname>. You can
iterate through the Rowset and access individual Row objects, reading or modifying data
in the Rows.
</para>
</sect2>
<sect2 id="zend.db.table.rowset.fetch">
<title>Fetching a Rowset</title>
<para>
<classname>Zend_Db_Table_Abstract</classname> provides methods
<methodname>find()</methodname> and <methodname>fetchAll()</methodname>, each of which
returns an object of type <classname>Zend_Db_Table_Rowset_Abstract</classname>.
</para>
<example id="zend.db.table.rowset.fetch.example">
<title>Example of fetching a rowset</title>
<programlisting language="php"><![CDATA[
$bugs = new Bugs();
$rowset = $bugs->fetchAll("bug_status = 'NEW'");
]]></programlisting>
</example>
</sect2>
<sect2 id="zend.db.table.rowset.rows">
<title>Retrieving Rows from a Rowset</title>
<para>
The Rowset itself is usually less interesting than the Rows that it contains. This
section illustrates how to get the Rows that comprise the Rowset.
</para>
<para>
A legitimate query returns zero rows when no rows in the database match the query
conditions. Therefore, a Rowset object might contain zero Row objects. Since
<classname>Zend_Db_Table_Rowset_Abstract</classname> implements the
<classname>Countable</classname> interface, you can use <methodname>count()</methodname>
to determine the number of Rows in the Rowset.
</para>
<example id="zend.db.table.rowset.rows.counting.example">
<title>Counting the Rows in a Rowset</title>
<programlisting language="php"><![CDATA[
$rowset = $bugs->fetchAll("bug_status = 'FIXED'");
$rowCount = count($rowset);
if ($rowCount > 0) {
echo "found $rowCount rows";
} else {
echo 'no rows matched the query';
}
]]></programlisting>
</example>
<example id="zend.db.table.rowset.rows.current.example">
<title>Reading a Single Row from a Rowset</title>
<para>
The simplest way to access a Row from a Rowset is to use the
<methodname>current()</methodname> method. This is particularly appropriate when the
Rowset contains exactly one Row.
</para>
<programlisting language="php"><![CDATA[
$bugs = new Bugs();
$rowset = $bugs->fetchAll("bug_id = 1");
$row = $rowset->current();
]]></programlisting>
</example>
<para>
If the Rowset contains zero rows, <methodname>current()</methodname> returns
<acronym>PHP</acronym>'s <constant>NULL</constant> value.
</para>
<example id="zend.db.table.rowset.rows.iterate.example">
<title>Iterating through a Rowset</title>
<para>
Objects descending from <classname>Zend_Db_Table_Rowset_Abstract</classname>
implement the <classname>SeekableIterator</classname> interface, which means you can
loop through them using the <methodname>foreach()</methodname> construct. Each value
you retrieve this way is a <classname>Zend_Db_Table_Row_Abstract</classname> object
that corresponds to one record from the table.
</para>
<programlisting language="php"><![CDATA[
$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();
}
]]></programlisting>
</example>
<example id="zend.db.table.rowset.rows.seek.example">
<title>Seeking to a known position into a Rowset</title>
<para>
<classname>SeekableIterator</classname> allows you to seek to a position that you
would like the iterator to jump to. Simply use the <methodname>seek()</methodname>
method for that. Pass it an integer representing the number of the Row you would
like your Rowset to point to next, don't forget that it starts with index 0. If the
index is wrong, ie doesn't exist, an exception will be thrown. You should use
<methodname>count()</methodname> to check the number of results before seeking to a
position.
</para>
<programlisting language="php"><![CDATA[
$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();
]]></programlisting>
</example>
<para>
<methodname>getRow()</methodname> allows you to get a specific row in the Rowset,
knowing its position; don't forget however that positions start with index zero. The
first parameter for <methodname>getRow()</methodname> is an integer for the position
asked. The second optional parameter is a boolean; it tells the Rowset iterator if
it must seek to that position in the same time, or not (default is
<constant>FALSE</constant>). This method returns a
<classname>Zend_Db_Table_Row</classname> object by default. If the
position requested does not exist, an exception will be thrown. Here is an example:
</para>
<programlisting language="php"><![CDATA[
$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();
]]></programlisting>
<para>
After you have access to an individual Row object, you can manipulate the Row using
methods described in <link linkend="zend.db.table.row">Zend_Db_Table_Row</link>.
</para>
</sect2>
<sect2 id="zend.db.table.rowset.to-array">
<title>Retrieving a Rowset as an Array</title>
<para>
You can access all the data in the Rowset as an array using the
<methodname>toArray()</methodname> method of the Rowset object. This returns an array
containing one entry per Row. Each entry is an associative array having keys that
correspond to column names and elements that correspond to the respective column values.
</para>
<example id="zend.db.table.rowset.to-array.example">
<title>Using toArray()</title>
<programlisting language="php"><![CDATA[
$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";
}
]]></programlisting>
</example>
<para>
The array returned from <methodname>toArray()</methodname> is not updateable. That is,
you can modify values in the array as you can with any array, but changes to the array
data are not propagated to the database.
</para>
</sect2>
<sect2 id="zend.db.table.rowset.serialize">
<title>Serializing and Unserializing a Rowset</title>
<para>
Objects of type <classname>Zend_Db_Table_Rowset_Abstract</classname> are serializable.
In a similar fashion to serializing an individual Row object, you can serialize a Rowset
and unserialize it later.
</para>
<example id="zend.db.table.rowset.serialize.example.serialize">
<title>Serializing a Rowset</title>
<para>
Simply use <acronym>PHP</acronym>'s <methodname>serialize()</methodname> function to
create a string containing a byte-stream representation of the Rowset object
argument.
</para>
<programlisting language="php"><![CDATA[
$bugs = new Bugs();
$rowset = $bugs->fetchAll();
// Convert object to serialized form
$serializedRowset = serialize($rowset);
// Now you can write $serializedRowset to a file, etc.
]]></programlisting>
</example>
<example id="zend.db.table.rowset.serialize.example.unserialize">
<title>Unserializing a Serialized Rowset</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 Rowset object returned is in a <emphasis>disconnected</emphasis>
state. You can iterate through the Rowset and read the Row objects and their
properties, but you cannot change values in the Rows or execute other methods that
require a database connection (for example, queries against related tables).
</para>
<programlisting language="php"><![CDATA[
$rowsetDisconnected = unserialize($serializedRowset);
// Now you can use object methods and properties, but read-only
$row = $rowsetDisconnected->current();
echo $row->bug_description;
]]></programlisting>
</example>
<note>
<title>Why do Rowsets 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>
<para>
You can reactivate a disconnected Rowset 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
Rowset, the Rowset gains access to the database. Subsequently, you can change values in
the Row objects contained in the Rowset and save the changes to the database.
</para>
<example id="zend.db.table.rowset.serialize.example.set-table">
<title>Reactivating a Rowset as Live Data</title>
<programlisting language="php"><![CDATA[
$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();
]]></programlisting>
</example>
<para>
Reactivating a Rowset with <methodname>setTable()</methodname> also reactivates all the
Row objects contained in that Rowset.
</para>
</sect2>
<sect2 id="zend.db.table.rowset.extending">
<title>Extending the Rowset class</title>
<para>
You can use an alternative concrete class for instances of Rowsets
by extending <classname>Zend_Db_Table_Rowset_Abstract</classname>. Specify the custom
Rowset class by name either in the <varname>$_rowsetClass</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.rowset.extending.example">
<title>Specifying a custom Rowset class</title>
<programlisting language="php"><![CDATA[
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'));
]]></programlisting>
</example>
<para>
Typically, the standard <classname>Zend_Db_Rowset</classname> concrete class is
sufficient for most usage. However, you might find it useful
to add new logic to a Rowset, specific to a given Table.
For example, a new method could calculate an aggregate
over all the Rows in the Rowset.
</para>
<example id="zend.db.table.rowset.extending.example-aggregate">
<title>Example of Rowset class with a new method</title>
<programlisting language="php"><![CDATA[
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';
}
]]></programlisting>
</example>
</sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
|