====== Создание новых 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]].