我的客户希望根据类别使用许多不同类型的属性构建产品目录。客户还希望具有相当全面的搜索功能,可以检查产品名称及其属性。所需的显示格式按类别分组,然后是与搜索词匹配的产品表。
Category
- name (string)
- products (1-to-Many:Product)
- attributes (1-to-Many:Attribute)
Attribute
- name (string)
- isDropdown (bool) - flag meaning can either be custom or from the dropdown options
- attributeOptions (1-to-Many:AttributeOption)
AttributeOption
- attribute (Many-to-1:Attribute)
- value
ProductAttributeValue
- attribute (Many-to-1:Attribute)
- selectedOption (Many-to-1:AttributeOption)
- value (string)
Product
- name (string)
- attributeValues (1-to-Many:ProductAttributeValue)
- category (Many-to-1:Category)
按产品名称搜索非常简单:
$search = 'gloves and stuff';
$searchTerms = explode(' ', $search);
$categoriesWithProducts = $em->createQueryBuilder()
->select('c, p, a, av, ao')
->from('AcmeBundle:Category', 'c')
->innerJoin('c.products', 'p')
->leftJoin('c.attributes', 'a')
->leftJoin('p.attributeValues', 'av')
->leftJoin('av.selectedOption', 'ao')
;
$i = 0;
foreach ($searchTerm as $st) {
$categoriesWithProducts
->orWhere('p.name LIKE ?'.$i)
->setParameter($i++, '%' . $st . '%')
;
}
$categoriesWithProducts = $categoriesWithProducts->getQuery()->getResult();
使用此Twig代码实现输出:
{% for category in categoriesWithProducts %}
<h2>{{ category.name }}</h2>
<table>
<thead>
{% for attribute in category.attributes %}
<th>{{ attribute.name }}</th>
{% endfor %}
</thead>
<tbody>
{% for product in category.products %}
<tr>
<td>{{ product.name }}</td>
{% for product in category.attributes %}
<td>
{% for attributeValue in product.attributeValues if attributeValue.attribute == attribute %}
{{ attribute.isDropdown ? attributeValue.selectedOption.value : attributeValue.value }}
{% endfor %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
结果输出:
但是,当我修改查询以匹配搜索词中的属性时:
$categoriesWithProducts = $em->createQueryBuilder()
->select('c, p, a, av, ao')
->from('AcmeBundle:Category', 'c')
->innerJoin('c.products', 'p')
->leftJoin('c.attributes', 'a')
->leftJoin('p.attributeValues', 'av')
->leftJoin('av.selectedOption', 'ao')
;
$i = 0;
foreach ($searchTerm as $st) {
$categoriesWithProducts
->orWhere('p.name LIKE ?'.$i)
->orWhere('av.value LIKE ?'.$i)
->orWhere('ao.value LIKE ?'.$i)
->setParameter($i++, '%' . $st . '%')
;
}
搜索仍然适用于匹配的产品名称,但会在attributeValues
字词匹配时生成selectedOption
和$search
的子集。例如,使用$search = 'red'
:
$search = 'red small'
:
我尝试为两个关联实体使用两个连接,但最终在我的结果集中获得重复项,这会在我的Twig渲染中产生双输出。
代码:
$categoriesWithProducts = $em->createQueryBuilder()
->select('c, p, a, av, ao, avSearch, aoSearch')
->from('AcmeBundle:Category', 'c')
->innerJoin('c.products', 'p')
->leftJoin('c.attributes', 'a')
->leftJoin('p.attributeValues', 'av')
->leftJoin('av.selectedOption', 'ao')
->leftJoin('p.attributeValues', 'avSearch')
->leftJoin('av.selectedOption', 'aoSearch')
;
$i = 0;
foreach ($searchTerm as $st) {
$categoriesWithProducts
->orWhere('p.name LIKE ?'.$i)
->orWhere('avSearch.value LIKE ?'.$i)
->orWhere('aoSearch.value LIKE ?'.$i)
->setParameter($i++, '%' . $st . '%')
;
}
$search = 'gloves and stuff'
的结果:
使用$search = 'red small'
(请注意重复的Red
和Small
条目,但其他属性只有奇异的结果):
我尝试了多种隐藏aoSearch
和avSearch
结果的方法:
HIDDEN aoSearch
而HIDDEN avSearch
无效aoSearch
中移除avSearch
和SELECT
会恢复到第2和第3个屏幕截图中发现的损坏子集问题。如果在任何Product的属性中找到匹配项,我希望获得表中显示的产品的所有属性。 有没有办法可以隐藏我错过的aoSearch
和avSearch
的匹配项?
答案 0 :(得分:1)
发布此问题后半小时,我有一个解决方法:
到目前为止,我找到解决方案的唯一方法是在单个EXISTS
子句中使用orWhere
函数,以便匹配包含在子查询中:
$categoriesWithProducts = $em->createQueryBuilder()
->select('c, p, a, av, ao')
->from('AcmeBundle:Category', 'c')
->innerJoin('c.products', 'p')
->leftJoin('c.attributes', 'a')
->leftJoin('p.attributeValues', 'av')
->leftJoin('av.selectedOption', 'ao')
;
$i = 0;
$subQuery = '';
foreach ($searchTerm as $st) {
if ($i > 0) $subQuery .= ' OR ';
$subQuery = 'sao.text LIKE ?'.$i.' OR pav.text LIKE ?'.$i;
$categoriesWithProducts
->orWhere('p.name LIKE ?'.$i)
->setParameter($i++, '%' . $st . '%')
;
}
$categoriesWithProducts->orWhere(
'EXISTS (
SELECT pav
FROM AcmeBundle:ProductAttributeValue pav
LEFT JOIN pav.selectedOption sao
WHERE pav.product = p AND ('.$subQuery.'))
');
$categoriesWithProducts = $categoriesWithProducts->getQuery()->getResult();
这为我提供了丰富的搜索结果!