搜索並不昂貴,人們只會在一個搜索查詢中的幾個位置搜索。
所以我做的第一件事就是加載所有搜索到的位置的ID以及所有父母的ID。
獲得父母的IDS:BaseTreeFacade::getPathIds
public function getPathIds($entity)
{
$ids = $this->getPathQueryBuilder($entity)
->select('node.id')
->getQuery()
->getResult(AbstractQuery::HYDRATE_SCALAR);
return array_map('current', $ids);
}
此方法返回與IDS簡單陣列。現在我必須通過搜索查詢和父母的ID一起加入ID。
擴大IDS:Helpers::expandTreeValues
public static function expandTreeValues(BaseTreeFacade $facade, array $values)
{
$result = [];
foreach ($values as $id) {
$entity = $facade->findOneById($id);
$result[] = [$id];
$result[] = $facade->getPathIds($entity);
}
$result = call_user_func_array('array_merge', $result);
$result = array_unique($result, SORT_NUMERIC);
return $result;
}
下一步是在位置和他們的孩子尋找創建where子句。
創建where子句:Helpers::prepareWhereClauseForChildren
public static function prepareWhereClauseForChildren(BaseTreeFacade $facade, array $values)
{
$where = [];
$parameters = [];
foreach ($values as $id) {
$entity = $facade->findOneById($id);
$where[] = "(l.lvl > :level$id AND l.id > :left$id AND l.id < :right$id)";
$parameters["left$id"] = $entity->lft;
$parameters["right$id"] = $entity->rgt;
$parameters["level$id"] = $entity->lvl;
}
$where = implode(' OR ', $where);
return (object) [
'where' => $where === '' ? null : $where,
'parameters' => count($parameters) === 0 ? null : $parameters,
];
}
在那裏,我可以,因爲樹的左右分支的所有子地點進行搜索。最後一步是使用上一步創建的where子句更新原始QueryBuilder
。
結束寫入的QueryBuilder:Helpers::updateWithTreeEntity
public static function updateWithTreeEntity(QueryBuilder $qb, array $values, $addWhere = null, array $addParameters = null)
{
if ($addParameters === null) {
$addParameters = [];
}
$addParameters['locations'] = $values;
$appendQuery = $addWhere === null ? '' : " OR $addWhere";
$qb->andWhere("l.id IN (:locations)$appendQuery");
foreach ($addParameters as $key => $value) {
$qb->setParameter($key, $value);
}
}
用例:
public function createQueryBuilderForSearchingInLocations(array $locations)
{
$gb = $this->createQueryBuilderSomehow();
$facade = $this->getLocationsFacadeSomehow();
$locations = Helpers::expandTreeValues($facade, $locations);
$where = Helpers::prepareWhereClauseForChildren($facade, $locations);
Helpers::updateWithTreeEntity($qb, $locations, $where->where, $where->parameters);
return $qb;
}