最近我一直在处理一堆将 Doctrine 1.2 集成到 Zend Framework 1.11 中的项目,这真的很有趣。
我在服务层中实现的最常见方法之一是根据作为参数传递的一组标准返回我的域模型集合的方法。
我一直在用这样的接口创建它们:
//All books
$books = $service->getBooks();
//Books under certain categories and authored which matches the search term 'Hitchens'
$books = $service->getBooks(array(
'category' => array(1,2,3,4),
'author' => array('like' => '%Hitchens%', 'diedBefore' => Zend_Date::now()),
'orderBy' => 'bookTitle',
'limit' => 10
));
实现如下所示:
public function getBooks(array $options = null)
{
$query = Doctrine_Query::create()->from('LibSys_Model_Book as book');
if($options !== null){
if(isset($options['author']){
//Manipulate Doctrine_Query object here....
}
//More 'ifs' and manipulations to the Doctrine_Query object...(additional criterias, orderBy clauses, limits, offsets, etc.)
}
}
随着我对更多标准的需求增加,实现变得更加混乱。不用说,到处都有大量的代码重用,更新代码是一项如此乏味的任务。
我一直在想,如果我可以将标准作为对象而不是数组段传递,使用访问者模式和这样的东西会更好:
$authorCriteria = new LibSys_Criteria_Author();
$authorCriteria->like('%Hitchens%');
$authorCriteria->diedBefore(Zend_Date::now());
$books = $service->getBooks(array(
$authorCriteria,
new LibSys_Criteria_Category(array(1,2,3,4))
));
使用LibSys_Criteria_Category
并LibSys_Criteria_Author
实现一个可能如下所示的通用接口:
interface LibSys_Doctrine_Criteria_Interface
{
public function applyCriteria(Doctrine_Query $query);
}
因此,只需遍历提供的一组标准对象并将Doctrine_Query
对象传递给它们,因为它们轮流操作它以满足需求:
public function getBooks(array $criteria = null)
{
$query = Doctrine_Query::create()->from('LibSys_Model_Book as book');
if($criteria !== null){
foreach($criteria as $criterion){
if($criterion instanceof LibSys_Doctrine_Criteria_Interface){
$criterion->applyCriteria($query);
}
}
}
}
这种方式不仅使它们更易于使用,而且使服务可扩展,标准对象可重用,并且一切都更易于维护。
但是,为了使这项工作更加稳健,需要能够检查Doctrine_Query
对象并检查任何现有的连接、条件等。这是因为两个完全不同的标准可能需要相同的一组条件或相同的条件并非不可能连接集。在这种情况下,第二个标准可以简单地重新使用现有的连接和/或相应地进行调整。此外,不难想象一个标准的一组条件与另一个条件相互不兼容的情况,在这种情况下应该保证抛出异常。
所以我的问题是:
有没有办法检查Doctrine_Query
并获取有关已加入哪些组件或已应用于它的任何条件集的信息?