1 <sect1 id="zend.db.table.row">
3 <title>Zend_Db_Table_Row</title>
5 <sect2 id="zend.db.table.row.introduction">
7 <title>Введение</title>
10 Zend_Db_Table_Row является классом, содержащим отдельную строку
11 объекта Zend_Db_Table. Когда вы производите запрос через класс
12 таблицы, результат возвращается в виде набора объектов
13 Zend_Db_Table_Row. Вы можете также использовать этот объект для
14 создания новых строк и их добавления в таблицу БД.
18 Zend_Db_Table_Row является реализацией паттерна
19 <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data Gateway</ulink>.
24 <sect2 id="zend.db.table.row.read">
26 <title>Извлечение строки</title>
29 Zend_Db_Table_Abstract предоставляет методы <code>find()</code> и
30 <code>fetchAll()</code>, которые возвращают объект типа
31 Zend_Db_Table_Rowset, и метод <code>fetchRow()</code>, возвращающий
32 объект типа Zend_Db_Table_Row.
35 <example id="zend.db.table.row.read.example">
37 <title>Пример извлечения строки</title>
39 <programlisting language="php"><![CDATA[
41 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
48 Объект Zend_Db_Table_Rowset содержит коллекцию объектов
49 Zend_Db_Table_Row. Для получения более подробной информации
50 читайте <xref linkend="zend.db.table.rowset" />.
53 <example id="zend.db.table.row.read.example-rowset">
55 <title>Пример получения строки из набора строк</title>
57 <programlisting language="php"><![CDATA[
59 $rowset = $bugs->fetchAll($bugs->select()->where('bug_status = ?', 1));
60 $row = $rowset->current();
66 <sect3 id="zend.db.table.row.read.get">
67 <title>Чтение значений столбцов из строки</title>
70 Zend_Db_Table_Row_Abstract предоставляет методы-аксессоры,
71 благодаря которым можно ссылаться на столбцы в строке как на
75 <example id="zend.db.table.row.read.get.example">
77 <title>Пример чтения столбца из строки</title>
79 <programlisting language="php"><![CDATA[
81 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
83 // Вывод значения столбца bug_description
84 echo $row->bug_description;
93 Более ранние версии Zend_Db_Table_Row сопоставляли
94 аксессоры столбцов и имена столбцов в БД с использованием
95 преобразования строк, называемым
96 <emphasis>инфлекцией</emphasis>.
100 Zend_Db_Table_Row в его текущей реализации не использует
101 инфлекцию. Написание аксессоров столбцов должно в точности
102 соответствовать именам столбцов, так, как они представлены в
110 <sect3 id="zend.db.table.row.read.to-array">
112 <title>Получение данных строки в виде массива</title>
115 Вы можете получать данные строки, используя метод
116 <code>toArray()</code> объекта строки. Метод возвращает
117 ассоциативный массив имен столбцов и их значений.
120 <example id="zend.db.table.row.read.to-array.example">
122 <title>Пример использования метода toArray()</title>
124 <programlisting language="php"><![CDATA[
126 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
128 // Получение ассоциативного массива столбцов и их значений из объекта Row
129 $rowArray = $row->toArray();
131 // Теперь используется как обычный массив
132 foreach ($rowArray as $column => $value) {
133 echo "Column: $column\n";
134 echo "Value: $value\n";
142 Массив, возвращаемый методом <code>toArray()</code> не может
143 использоваться для обновления данных в БД. Мы можете изменять
144 значения в этом массиве так же, как и в любом другом массиве, но
145 не можете сохранять измененные значения непосредственно из этого
151 <sect3 id="zend.db.table.row.read.relationships">
153 <title>Извлечение данных из связанных таблиц</title>
156 Класс Zend_Db_Table_Row_Abstract предоставляет методы для
157 извлечения строк и наборов строк из связанных таблиц.
158 Читайте <xref linkend="zend.db.table.relationships" /> для
159 получения более подробной информации о связях между таблицами.
166 <sect2 id="zend.db.table.row.write">
168 <title>Редактирование строк в БД</title>
170 <sect3 id="zend.db.table.row.write.set">
172 <title>Изменение значений столбцов в строке</title>
175 Используя аксессоры столбцов, вы можете устанавливать значения
176 отдельных столбцов по аналогии с чтением, т.е. так же, как если
177 бы они были свойствами объекта.
181 Использование аксессоров столбцов для установки значений
182 изменяет значения столбцов в данном объекте строки, но
183 эти изменения еще не фиксируются в БД. Вы можете произвести
184 фиксацию через метод <code>save()</code>.
187 <example id="zend.db.table.row.write.set.example">
189 <title>Пример изменения значения столбца в строке</title>
191 <programlisting language="php"><![CDATA[
193 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
195 // Изменение значения одного или более столбцов
196 $row->bug_status = 'FIXED';
198 // Обновление строки в БД с новыми значениями
207 <sect3 id="zend.db.table.row.write.insert">
209 <title>Вставка новой строки</title>
212 Вы можете создавать новые строки для определенной таблицы с
213 помощью метода <code>createRow()</code> класса таблицы. Можно
214 работать с полями этой строки через объектно-ориентированный
215 интерфейс, но строка не сохраняется в БД до тех пор, пока вы не
216 вызовете метод <code>save()</code>.
219 <example id="zend.db.table.row.write.insert.example">
221 <title>Пример создания новой строки таблицы</title>
223 <programlisting language="php"><![CDATA[
225 $newRow = $bugs->createRow();
227 // Установка значений столбцов
228 $newRow->bug_description = '...description...';
229 $newRow->bug_status = 'NEW';
231 // Вставка новой строки в БД
238 Опциональный аргумент метода является ассоциативным массивом,
239 через который вы можете заполнить поля новой строки.
242 <example id="zend.db.table.row.write.insert.example2">
244 <title>Пример заполнения новой строки для таблицы</title>
246 <programlisting language="php"><![CDATA[
248 'bug_description' => '...description...',
249 'bug_status' => 'NEW'
253 $newRow = $bugs->createRow($data);
255 // вставка новой строки в БД
264 В более ранних релизах Zend_Db_Table метод
265 <code>createRow()</code> назывался <code>fetchNew()</code>.
266 Мы рекомендуем использовать новое имя метода,
267 несмотря на то, что старое имя метода по-прежнему работает
268 в целях обеспечения обратной совместимости.
274 <sect3 id="zend.db.table.row.write.set-from-array">
276 <title>Изменение значений в нескольких столбцах</title>
279 Zend_Db_Table_Row_Abstract предоставляет метод
280 <code>setFromArray()</code> для того, чтобы можно было
281 устанавливать значения нескольких столбцов одновременно,
282 определив ассоциативный массив имен столбцов и их значений.
283 Этот метод может быть удобным как при создании новых строк, так
284 и при обновлении существующих.
287 <example id="zend.db.table.row.write.set-from-array.example">
289 <title>Пример использования метода setFromArray() для установки
290 значений в новой строке</title>
292 <programlisting language="php"><![CDATA[
294 $newRow = $bugs->createRow();
296 // Данные помещаются в ассоциативный массив
298 'bug_description' => '...description...',
299 'bug_status' => 'NEW'
302 // Одновременная установка значений всех столбцов
303 $newRow->setFromArray($data);
305 // Добавление новой строки в БД
314 <sect3 id="zend.db.table.row.write.delete">
316 <title>Удаление строки</title>
319 Вы можете использовать метод <code>delete()</code> объекта
320 строки. Этот метод удаляет из таблицы строки, соответствующие
321 первичному ключу в объекте строки.
324 <example id="zend.db.table.row.write.delete.example">
326 <title>Пример удаления строки</title>
328 <programlisting language="php"><![CDATA[
330 $row = $bugs->fetchRow('bug_id = 1');
340 Не нужно вызывать метод <code>save()</code> для фиксации
341 удаления, оно сразу выполняется в БД.
348 <sect2 id="zend.db.table.row.serialize">
350 <title>Сериализация и десериализация строк</title>
353 Часто бывает удобным сохранять содержимое строки БД для последующего
354 использования. <emphasis>Сериализацией</emphasis> называется
355 действие по преобразованию объекта в форму, удобную для хранения в
356 автономном хранилище (например, в файле). Объекты типа
357 Zend_Db_Table_Row_Abstract доступны для сериализации.
360 <sect3 id="zend.db.table.row.serialize.serializing">
362 <title>Сериализация объекта строки</title>
365 Просто используйте функцию PHP <code>serialize()</code> для
366 получения строки, содержащей представление объекта Row в виде
367 последовательности байт.
370 <example id="zend.db.table.row.serialize.serializing.example">
372 <title>Пример сериализации объекта строки</title>
374 <programlisting language="php"><![CDATA[
376 $row = $bugs->fetchRow('bug_id = 1');
378 // Преобразование объекта в сериализованную форму
379 $serializedRow = serialize($row);
381 // Теперь вы можете записать $serializedRow в файл и т.д.
389 <sect3 id="zend.db.table.row.serialize.unserializing">
391 <title>Десериализация данных строки</title>
394 Используйте функцию <code>unserialize()</code> для
395 восстановления из строки, содержащей представление объекта в
396 виде последовательности байт. Эта функция возвращает исходный объект.
400 Внимание: объект строки возвращается
401 <emphasis>без соединения</emphasis>. Вы можете читать объект Row
402 и его свойства, но не можете изменять значения в строке или
403 выполнять другие методы, требующие соединения с БД (например,
404 запросы к связанным таблицам).
407 <example id="zend.db.table.row.serialize.unserializing.example">
409 <title>Пример десериализации объекта строки</title>
411 <programlisting language="php"><![CDATA[
412 $rowClone = unserialize($serializedRow);
414 // Теперь вы можете использовать свойства объекта, но только для чтения
415 echo $rowClone->bug_description;
423 <title>Почему объекты строки десериализуются без соединения?</title>
426 Сериализованный объект является строкой, которая доступна
427 для чтения всем, кто ею обладает.
428 Это создает угрозу безопасности, которая состоит в
429 том, что в сериализованной строке сохраняются такие
430 параметры, как логин и пароль для соединения с БД, в
431 незашифрованном виде.
432 Для вас может быть нежелательным сохранять такие данные в
433 незащищенном текстовом файле, отправлять его через e-mail
434 или любой другой носитель, который может быть прочитан
435 потенциальным атакующим.
436 Тот, кто прочитает сериализованный объект, не должен иметь
437 возможности использовать его в получении
438 несанкционированного доступа к БД.
445 <sect3 id="zend.db.table.row.serialize.set-table">
447 <title>Восстановление соединения для объекта строки</title>
450 Вы можете восстановить соединение для строки, используя метод
451 <code>setTable()</code>. Аргументом этого метода является объект
452 типа Zend_Db_Table_Abstract, который создается вами. Создание
453 объекта таблицы требует действующего соединения с БД, поэтому
454 при переустановке таблицы объект строки получает доступ к БД.
455 После этого можно изменять значения в объекте строки и
456 сохранять изменения в БД.
459 <example id="zend.db.table.row.serialize.set-table.example">
461 <title>Пример восстановления соединения для строки</title>
463 <programlisting language="php"><![CDATA[
464 $rowClone = unserialize($serializedRow);
468 // Привязка строки к таблице с действующим соединением БД
469 $rowClone->setTable($bugs);
471 // Теперь вы можете производить изменения в строке и сохранять их
472 $rowClone->bug_status = 'FIXED';
483 <sect2 id="zend.db.table.row.extending">
485 <title>Расширение класса строки</title>
488 Zend_Db_Table_Row является используемым по умолчанию классом,
489 который наследует от Zend_Db_Table_Row_Abstract. Вы можете
490 определить свой собственный класс для экземпляров строк путем
491 наследования от Zend_Db_Table_Row_Abstract. Для того, чтобы этот
492 класс использовался для хранения результатов запросов к таблице,
493 укажите его имя в защищенном свойстве <varname>$_rowClass</varname>
494 класса таблицы или в массиве, передаваемом в качестве аргумента
495 конструктору объекта таблицы.
498 <example id="zend.db.table.row.extending.example">
500 <title>Указание своего класса строки</title>
502 <programlisting language="php"><![CDATA[
503 class MyRow extends Zend_Db_Table_Row_Abstract
508 // Укажите свой класс строки в качестве используемого по умолчанию
509 // во всех экземплярах класса таблицы
510 class Products extends Zend_Db_Table_Abstract
512 protected $_name = 'products';
513 protected $_rowClass = 'MyRow';
516 // Или укажите свой класс строки для использования
517 // в конкретном экземпляре класса таблицы
518 $bugs = new Bugs(array('rowClass' => 'MyRow'));
524 <sect3 id="zend.db.table.row.extending.overriding">
526 <title>Инициализация строки</title>
529 Если при создании объекта строки требуется выполнять код,
530 реализующий логику приложения, то вы можете поместить этот код в
531 метод <code>init()</code>, который вызывается после того,
532 как были обработаны все метаданные строки. Рекомендуется
533 использовать этот способ вместо переопределения метода
534 <code>__construct</code>, если только не требуется изменять
535 метаданные программным путем.
537 <example id="zend.db.table.row.init.usage.example">
539 <title>Пример использования метода init()</title>
541 <programlisting language="php"><![CDATA[
542 class MyApplicationRow extends Zend_Db_Table_Row_Abstract
546 public function init()
548 $this->_role = new MyRoleClass();
560 <sect3 id="zend.db.table.row.extending.insert-update">
562 <title>Определение собственной логики для добавления, обновления и удаления в Zend_Db_Table_Row</title>
565 Класс строки вызывает защищенные методы <code>_insert()</code>,
566 <code>_update()</code> и <code>_delete()</code> до выполнения
567 соответствующих операций <code>INSERT</code>,
568 <code>UPDATE</code> и <code>DELETE</code>. Вы можете добавлять
569 собственную логику в эти методы в созданном вами подклассе
574 Если нужно выполнение собственной логики в определенной
575 таблице, и эта логика должна выполняться для каждой операции в
576 этой таблице, то разумным решением может быть реализация
577 собственной логики в методах <code>insert()</code>,
578 <code>update()</code> и <code>delete()</code> вашего класса
579 таблицы. Тем не менее, иногда может быть необходимым выполнять
580 собственную логику в классе строки.
584 Ниже приведены примеры случаев, в которых имеет смысл
585 реализовать свою логику в классе строки вместо класса
589 <example id="zend.db.table.row.extending.overriding-example1">
590 <title>Пример собственной логики в классе строки</title>
593 Собственная логика может применяться не во всех случаях
594 операций над определенной таблицей. Вы можете реализовать
595 свою логику в классе строки и создавать экземпляр класса
596 таблицы с указанием этого класса строки в качестве
597 используемого. Иначе в таблице используется класс
602 Вам нужно, чтобы операции над данными в этой таблице
603 журналировались через объект Zend_Log, но только если в
604 конфигурации приложения включено это поведение.
607 <programlisting language="php"><![CDATA[
608 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
610 protected function _insert()
612 $log = Zend_Registry::get('database_log');
613 $log->info(Zend_Debug::dump($this->_data,
614 "INSERT: $this->_tableClass",
620 // $loggingEnabled - свойство, используемое для примера и зависящее
621 // от конфигурации вашего приложения
622 if ($loggingEnabled) {
623 $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
632 <example id="zend.db.table.row.extending.overriding-example2">
634 <title>Пример класса строки, журналирующего добавляемые данные для нескольких таблиц</title>
637 Собственная логика может быть общей для нескольких таблиц.
638 Вместо реализации одной и той же логики в каждом классе
639 таблицы вы можете реализовать код этих действий в
640 классе строки и использовать этот класс строки во
641 всех ваших классах таблиц.
645 В этом примере журналирующий код одинаков для всех классов
649 <programlisting language="php"><![CDATA[
650 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
652 protected function _insert()
654 $log = Zend_Registry::get('database_log');
655 $log->info(Zend_Debug::dump($this->_data,
656 "INSERT: $this->_tableClass",
662 class Bugs extends Zend_Db_Table_Abstract
664 protected $_name = 'bugs';
665 protected $_rowClass = 'MyLoggingRow';
668 class Products extends Zend_Db_Table_Abstract
670 protected $_name = 'products';
671 protected $_rowClass = 'MyLoggingRow';
680 <sect3 id="zend.db.table.row.extending.inflection">
681 <title>Определение инфлекции в Zend_Db_Table_Row</title>
684 Некоторые разработчики предпочитают, чтобы имя класса таблицы
685 соответствовало имени таблицы в СУРБД с применением
686 преобразования, называемого <emphasis>инфлекцией</emphasis>.
690 Классы Zend_Db по умолчанию не производят
692 <xref linkend="zend.db.table.extending.inflection" /> для
693 получения информации о причинах такого решения.
697 Если вы предпочитаете использовать инфлекцию, то должны сами
698 реализовать преобразование, переопределив метод
699 <code>_transformColumn()</code> в своем классе строки и
700 использовать этот класс при произведении запросов через ваш
704 <example id="zend.db.table.row.extending.inflection.example">
706 <title>Пример определения инфлекционного преобразования</title>
709 Это позволяет использовать в аксессорах преобразованный
710 вариант имени столбца. Класс строки использует метод
711 <code>_transformColumn()</code> для преобразования имени,
712 которое используется в качестве "родного" имени столбца в
716 <programlisting language="php"><![CDATA[
717 class MyInflectedRow extends Zend_Db_Table_Row_Abstract
719 protected function _transformColumn($key)
721 $nativeKey = myCustomInflector($key);
726 class Bugs extends Zend_Db_Table_Abstract
728 protected $_name = 'bugs';
729 protected $_rowClass = 'MyInflectedRow';
733 $row = $bugs->createRow();
735 // Используются имена столбцов в формате CamelCase, преобразующая функция
736 // изменяет их представление на "родное"
737 $row->bugDescription = 'New description';
744 Реализация функций для произведения инфлекционного
745 преобразования возлагается на разработчика. Zend Framework не
746 предоставляет для этих целей готовых функций.