# Zend_Db_Table_Rowset

## Введение

Когда вы производите запрос через класс таблицы, используя методы `find()` или `fetchAll()`, результат возвращается в объекте типа `Zend_Db_Table_Rowset_Abstract`. Набор строк (rowset) содержит коллекцию объектов, наследующих от `Zend_Db_Table_Row_Abstract`. Вы можете производить итерацию по набору строк и работать с отдельными объектами строк, считывая или изменяя данные в строках.

## Получение набора строк

`Zend_Db_Table_Abstract` предоставляет методы `find()` и `fetchAll()`, оба они возвращают объект типа `Zend_Db_Table_Rowset_Abstract`.

### Пример извлечения набора строк

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

## Получение строк из набора

Обычно сам по себе набор строк представляет меньший интерес, чем строки, содержащиеся в нем. Этот раздел показывает, как получать строки из набора строк.

Правильно составленный запрос возвращает нулевое количество строк, если в БД нет строк, соответствующих условиям запроса. Поэтому объект набора строк может содержать нулевое количество объектов строк. Поскольку `Zend_Db_Table_Rowset_Abstract` реализует инерфейс `Countable`, то вы можете использовать `count()` для определения количества строк в наборе строк.

### Подсчет количества строк в наборе строк

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

    $rowCount = count($rowset);

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

### Чтение одной строки из набора строк

Наиболее простой способ получения доступа к строке из набора состоит в использовании метода `current()`. Этот способ особенно подходит для тех случаев, когда набор строк содержит только одну строку.

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

Если набор строк содержит нулевое количество строк, то `current()` вернет значение `NULL`.

### >Итерация по набору строк

Объекты, наследующие от `Zend_Db_Table_Rowset_Abstract`, реализуют интерфейс `Iterator`. Это значит, что можно производить циклический обход объектов, используя конструкцию `foreach()`. Каждое значение, получаемое таким образом, является объектом типа `Zend_Db_Table_Row_Abstract`, который соответствует одной записи в таблице.

    $bugs = new Bugs();

    // извлечение всех записей из таблицы
    $rowset = $bugs->fetchAll();

    foreach ($rowset as $row) {

        // выводит 'Zend_Db_Table_Row' или подобное
        echo get_class($row) . "\n";

        // чтение столбца в строке
        $status = $row->bug_status;

        // изменение столбца в текущей строке
        $row->assigned_to = 'mmouse';

        // сохранение изменений в БД
        $row->save();
    }

`getRow()` позволяет извлекать строку из набора строк, используя номер ее позиции, при этом не забывайте, что отсчет позиции начинается с нуля. Первый параметр метода `getRow()` должен быть целочисленным и используется для передачи позиции строки. Второй необязательный параметр должен иметь булев тип, при передаче значения true итератор перемещается в данную позицию (по умолчанию используется значение false). По умолчанию этот метод возвращает объект Zend_Db_Table_Row. Если запрошенная позиция не существует, то бросается исключение. Ниже приведен пример:

    $bugs = new Bugs();

    // извлечение всех строк из таблицы
    $rowset = $bugs->fetchAll();

    // извлечение девятой строки:
    $row9->getRow(8);

    // и ее применение:
    $row9->assigned_to = 'mmouse';
    $row9->save();

После того, как получен отдельный объект строки, вы можете работать с ним, используя методы, описанные в

## Получение набора строк в виде массива

Вы можете работать с данными в наборе строк как с массивом, используя метод `toArray()` объекта набора строк. Он возвращает массив, содержащий по одной записи на строку. Каждая запись является ассоциативным массивом, в котором ключи соответствуют именам столбцов, а элементы - значениям этих столбцов.

### Использование 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";
    }

Массив, возвращаемый методом `toArray()` не может использоваться для обновления данных в БД. Вы можете изменять значения в этом массиве так же, как и в любом другом массиве, но эти изменения не сохраняются в БД.

## Сериализация и десериализация наборов строк

Объекты типа `Zend_Db_Table_Rowset_Abstract` доступны для сериализации. Сериализация производится так же, как и для отдельных объектов строк - вы можете сериализовать объект набора строк и восстановить его позднее.

### Сериализация набора строк

Используйте PHP-функцию `serialize()` для получения строки, содержащей представление объекта набора строк в виде последовательности байт.

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

    // Преобразование объекта в сериализованную форму
    $serializedRowset = serialize($rowset);

    // Теперь вы можете записать $serializedRowset в файл и т.п.

### Десериализация набора строк

Используйте функцию `unserialize()` для восстановления из строки, содержащей представление объекта в виде последовательности байт. Эта функция возвращает исходный объект.

Внимание: объект набора строк возвращается без соединения с БД. Вы можете производить циклический обход набора строк, читать объекты строк и их свойства, но не изменять значения в строках или выполнять другие методы, требующие соединения с БД (например, запросы к связанным таблицам).

    $rowsetDisconnected = unserialize($serializedRowset);

    // Теперь вы можете использовать свойства и методы объекта, но только для чтения
    $row = $rowsetDisconnected->current();
    echo $row->bug_description;

### Почему объекты наборов строк десериализируются без соединения с БД?

Сериализованный объект является строкой, которая доступна для чтения всем, кто ею обладает. Это создает угрозу безопасности, которая состоит в том, что в сериализованной строке сохраняются такие параметры, как логин и пароль для соединения с БД, в незашифрованном виде. Для вас может быть нежелательным сохранять такие данные в незащищенном текстовом файле, отправлять его через e-mail или любой другой носитель, который может быть прочитан потенциальным атакующим. Тот, кто прочитает сериализованный объект, не должен иметь возможности использовать его для получения несанкционированного доступа к БД.

Вы можете восстановить соединение для набора строк, используя метод `setTable()`. Аргументом этого метода является объект типа `Zend_Db_Table_Abstract`, который создается вами. Создание объекта таблицы требует действующего соединения с БД, поэтому при переустановке таблицы объект набора строк получает доступ к БД. После этого вы сможете изменять значения объектов строк, содержащихся в объекте набора строк и сохранять изменения в БД.

### Пример восстановления соединения для набора строк

    $rowset = unserialize($serializedRowset);

    $bugs = new Bugs();

    // Переустановка таблицы для набора строк,
    // заодно восстанавливается соединение с БД
    $rowset->setTable($bugs);

    $row = $rowset->current();

    // Теперь можно производить изменения в строке и сохранять их
    $row->bug_status = 'FIXED';
    $row->save();

Восстановление соединения для набора строк через метод `setTable()` делает то же самое для всех объектов строк, содержащихся в этом наборе строк.

## Расширение класса набора строк

Вы можете использовать альтернативный класс для наборов строк путем расширения класса Zend_Db_Table_Rowset_Abstract. Указывайте новый класс набора строк через имя в защищенном свойстве `$_rowsetClass` класса таблицы или в массиве, передаваемом в качестве аргумента конструктору объекта таблицы.

### Указание своего класса набора строк

    class MyRowset extends Zend_Db_Table_Rowset_Abstract
    {
        // ...кастомизация
    }

    // Укажите свой класс набора строк в качестве используемого по умолчанию
    // во всех экземплярах класса таблицы
    class Products extends Zend_Db_Table_Abstract
    {
        protected $_name = 'products';
        protected $_rowsetClass = 'MyRowset';
    }

    // Или укажите свой класс набора строк для использования
    // в конкретном экземпляре класса таблицы

Стандартный класс Zend_Db_Rowset подходит для большинства случаев использования. Тем не менее, может потребоваться добавить свою логику в набор строк, специфический для данной таблицы. Например, новый метод может вычислять агрегированное значение для всех строк в наборе.

### Пример класса набора строк с новым методом

    class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract
    {
        /**
         * Находит в текущем наборе строку с наибольшим
         * значением в столбце 'updated_at'
         */
        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';
    }