====== Создание новых find() методов. Выполнение своих sql-запросов. ====== В процесс работы вам немременно необходимо будет создавать новые find() и get() методы в ваших ActiveRecord-ах. Мы для себя уславливаемся обычно, что find()-методы это статические методы, а getter-ы - это instance-методы, например: class Document extends lmbActiveRecord { static function findPublished() { $time = time(); return lmbActiveRecord :: find('Document', "is_published = 1 AND (date_start <= {$time} AND date_end >= {$time})"); } static function findKidsForParent($parent_id) { $sql = 'SELECT document.* '. ' FROM document LEFT JOIN node ON node.object_id = document.id '. ' WHERE node.parent_id = '. $parent_id; return lmbActiveRecord :: decorateRecordSet($this->_query($sql), 'Document'); } function getPublishedKids() { $sql = 'SELECT document.* '. ' FROM document LEFT JOIN node ON node.object_id = document.id '. ' WHERE node.parent_id = '. $this->getNode()->getId() . ' AND document.date_start <= :time: AND document.date_end >= :time:'. ' AND document.is_published = 1 ' . ' ORDER BY node.priority ASC,document.date DESC'; $stmt = $this->_createSQLStatement($sql); $stmt->setInteger('time', time()); return $this->decorateRecordSet($stmt->getRecordSet()); } } На что здесь нужно обратить внимание: $rs = $this->_query($sql); lmbActiveRecord :: **_query($sql)** возвращает объект типа RecordSet, который имплементирует интерфейс Iterator и позволяет пошагово перебрать всю выборку без лишних затрат памяти. $stmt = $this->_createSQLStatement($sql); lmbActiveRecord :: **_createSQLStatement($sql)** создает объект типа Statement, нужного класса, который зависит от типа используемого драйвера базы данных. Statement позволяет правильным образом установить параметры запроса, с учетом особенностей драйвера, как это сделано в методе Document :: getPublishedKids(). Обратите внимание также на следующие две строки: return lmbActiveRecord :: decorateRecordSet($stmt->getRecordSet(), 'Document'); и return $this->decorateRecordSet($stmt->getRecordSet()); По своей сути это - две одинаковые строки. Более правильно использовать именно первый вариант, так как lmbActiveRecord :: **decorateRecordSet($dataset, $class_name = null)** задумывался как статический метод. Суть применения этого метода - в декорировании RecordSet-а специальным декоратором (класса lmbARRecordSetDecorator), который из каждой записи итератора формирует полноценный ActiveRecord. После применения этого декоратора вы можете использовать все, что относится к ActiveRecord-ам, например, доступ к связям между объектами. В целях оптимизации вы можете не использовать этот декоратор в каких-то методах. Как вы поняли lmbActiveRecord :: **find($params = array())** и другие find()-методы применяют этот декоратор по-умолчанию. Стоит еще отметить, что в создаваемый ActiveRecord из записи итератора передаются все поля, даже если они не относятся непосредственно к ActiveRecord, поэтому иногда можно указывать дополнительное количество полей в выборках, например: class Document extends lmbActiveRecord { [...] static function findKidsForParent($parent_id) { $sql = 'SELECT document.*, node.identifier as node_identifier, node.title as node_title '. ' FROM document LEFT JOIN node ON node.object_id = document.id '. ' WHERE node.parent_id = '. $parent_id; return lmbActiveRecord :: decorateRecordSet($this->_query($sql), 'Document'); } [...] } Дополнительно о создании своих sql-запросов в описании [[limb3_2007_2:ru:packages:dbal|пакета DBAL]].