我们使用Doctrine 2进行数据库访问tree extension。
第一个表是树表,其中包含从此source创建的欧盟位置。
位置表:
id
name
parent
lft
rgt
lvl
root
companies
还有公司表保存与位置表有多对多关系的公司的一览表。这些地点是给定公司行为的地点。它可以是国家(0级),某些地区(1级,2级,3级,4级)或某些城市,城镇或村庄(5级)。
公司表:
id
name
locations
我们为有位置选择的公司提供了一个搜索表单。
现在我需要创建DQL,它将选择给定位置的所有国家/地区(嵌套)。
因此,当我选择整个国家时,应选择该国家,该国家/地区以及该国城镇的所有公司。
谢谢。
修改
我在公司中添加了“自动添加”(可能是临时的)父位置。它将遍历所有父母并添加它们。因此,当公司在城市行事并且用户选择整个国家或地区时,将显示该公司。
不幸的是还有一个问题。如果某个公司在全国范围内行事并且用户在该国家/地区选择城市,则不会显示公司。
答案 0 :(得分:0)
搜索不是那么昂贵,人们只会在一个搜索查询中搜索几个位置。
所以我做的第一件事就是加载所有搜索位置的ID以及所有父母的ID。
获取父母的ID BaseTreeFacade::getPathIds
public function getPathIds($entity)
{
$ids = $this->getPathQueryBuilder($entity)
->select('node.id')
->getQuery()
->getResult(AbstractQuery::HYDRATE_SCALAR);
return array_map('current', $ids);
}
此方法返回带有id的简单数组。现在我必须使用父母的ID来搜索查询中的ID。
展开ID 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;
}