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 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.db.table.row">
<title>Zend_Db_Table_Row</title>
<sect2 id="zend.db.table.row.introduction">
<title>Introduction</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 the chapter about <link
linkend="zend.db.table.rowset">table rowset</link> for details.
</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 the <link
linkend="zend.db.table.relationships">relationship chapter</link> 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 <methodname>createRow()</methodname> 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 <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 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.
</para>
<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>
</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 <constant>INSERT</constant>,
<constant>UPDATE</constant>, and <constant>DELETE</constant>. 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
the chapter about <link linkend="zend.db.table.extending.inflection">extending
inflection</link> 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>
<!--
vim:se ts=4 sw=4 et:
-->
|