dede如何同时满足两个筛选条件?

99ANYc3cd6
预计阅读时长 22 分钟
位置: 首页 DEDE建站 正文

下面我将通过一个详细的、可操作的例子来讲解如何实现,我们以一个常见的商品筛选为例,假设有两个筛选条件:

dede同时选两个筛选条件
(图片来源网络,侵删)
  1. 分类 (typeid)
  2. 品牌 (brand)

第一步:准备工作 (修改模板和创建表单)

  1. 修改列表模板文件 打开你的列表页模板文件,通常位于 /templets/你的栏目目录/list_栏目ID.htm,我们需要在这个文件里添加筛选表单。

  2. 添加筛选表单 在模板的合适位置(通常是列表上方)添加一个表单,这个表单将包含两个下拉选择框和一个提交按钮。

    <form name="searchform" action="" method="get">
        <!-- 隐藏域,用于传递当前栏目ID,确保筛选后仍在当前栏目下 -->
        <input type="hidden" name="typeid" value="{dede:type typeid='[field:id/]'}[field:id]{/dede:type}" />
        <!-- 筛选条件1:分类 -->
        <select name="typeid_filter">
            <option value="">所有分类</option>
            {dede:channel type='son' currentstyle="<option value='~typeid~' selected>~typename~</option>"}
            <option value="[field:id/]">[field:typename/]</option>
            {/dede:channel}
        </select>
        <!-- 筛选条件2:品牌 -->
        <select name="brand">
            <option value="">所有品牌</option>
            {dede:sql sql="SELECT DISTINCT brand FROM `dede_addonarticle` WHERE brand != '' ORDER BY brand ASC"}
            <option value="[field:brand/]">[field:brand/]</option>
            {/dede:sql}
        </select>
        <!-- 提交按钮 -->
        <button type="submit">筛选</button>
    </form>

    代码解释:

    • formmethod 必须是 get,这样筛选条件会以 URL 参数的形式传递(.../list.php?tid=1&brand=苹果)。
    • typeid_filterbrand 是我们为两个筛选条件自定义的参数名。
    • 品牌的下拉框是通过 dede:sql 标签直接从数据库中读取不重复的品牌列表,前提是你的自定义模型或文章模型中有一个名为 brand 的字段。

第二步:修改PHP文件 (处理逻辑)

这是最关键的一步,我们需要修改处理列表页的PHP文件,通常是 /include/arc.listview.class.php强烈建议在修改前备份这个文件!

dede同时选两个筛选条件
(图片来源网络,侵删)
  1. 打开 /include/arc.listview.class.php

  2. 找到 GetSql() 方法 这个方法负责生成最终的SQL查询语句,我们需要在这里添加逻辑来处理URL参数。

  3. 修改 GetSql() 方法 在这个方法中,找到构建 where 条件的部分(通常在方法的后半部分),然后添加我们的筛选逻辑。

    在类似这样的代码块附近进行修改:

    // ... 在 GetSql() 方法中找到 $this->addSql .= " And arc.typeid in($typeid)"; 这类代码之后 ...
    // --- 开始添加我们的筛选逻辑 ---
    if (!empty($this->searchArr['typeid_filter'])) {
        // 如果选择了分类筛选
        $this->addSql .= " And arc.typeid = '".$this->searchArr['typeid_filter']."'";
    }
    if (!empty($this->searchArr['brand'])) {
        // 如果选择了品牌筛选
        // 注意:这里假设你的品牌字段在附加表 dede_addonarticle 中
        // 如果是其他模型,请替换为对应的附加表名,如 dede_addonshopproduct
        $this->addSql .= " And arc.body LIKE '%".$this->searchArr['brand']."%'"; // 使用 body 字段模糊匹配,或者直接用 addon.brand
        // 更精确的做法是使用 JOIN 连接附加表,这需要更复杂的SQL修改
        // 对于初学者,先用 LIKE 模糊匹配是最简单的。
        // 如果你为品牌设置了独立的字段,并且附加表里有这个字段,可以这样写:
        // $this->addSql .= " And addontable.brand = '".$this->searchArr['brand']."'";
        // 但这通常需要先 JOIN 附加表。
    }
    // --- 结束添加我们的筛选逻辑 ---

    重要说明:

    • $this->searchArr 是一个数组,用来存储所有通过GET方式传递过来的URL参数。
    • 我们通过 !empty() 判断参数是否存在,如果存在,就将其拼接到SQL的 where 条件中。
    • 品牌匹配的SQL写法:上面的例子使用了 arc.body LIKE '%...%'',这是一种简单粗暴的模糊匹配,它会匹配文章内容中任何包含品牌名的记录。这不是最佳实践
    • 最佳实践(推荐):如果你的品牌是一个独立的、有索引的字段,你应该在附加表(如 dede_addonarticle)中操作,最规范的写法是使用 JOIN,但这需要对 GetSql() 方法进行更深入的改造,稍显复杂,对于大多数情况,先使用 LIKE 可以快速实现功能。

第三步:处理分页问题 (非常重要)

直接修改 GetSql() 会导致一个问题:分页失效,因为分页时,系统会重新调用 GetSql() 方法,但此时筛选参数已经丢失了。

为了解决这个问题,我们需要在 GetSql() 方法中增加一个逻辑,让它在生成分页SQL时,也带上筛选条件。

找到 GetPageListDT() 方法(或者类似处理分页的方法),确保它在调用 GetSql() 时,能将 $this->searchArr 传递过去,或者在 GetSql() 内部能持续访问到这些参数。

arc.listview.class.phpGetSql() 方法本身已经可以访问 $this->searchArr,所以理论上你的修改应该已经能支持分页,但如果你发现分页后筛选条件丢失,请检查 $this->addSql 变量在每次调用 GetSql() 时是否都被正确重置和构建。

一个更稳妥的方案是,在 GetSql() 方法开始处,就先构建好所有筛选条件,而不是在后面 if 判断。

改进后的 GetSql() 逻辑片段:

// 在 GetSql() 方法中,构建 where 条件的部分
$where = " arc.arcrank > -1 ";
// ... 其他默认条件 ...
// --- 添加我们的筛选逻辑 ---
if (!empty($this->searchArr['typeid_filter'])) {
    $where .= " AND arc.typeid = '".$this->searchArr['typeid_filter']."'";
}
if (!empty($this->searchArr['brand'])) {
    // 假设品牌在附加表的 brand 字段
    // 为了能使用 addontable.brand,我们需要先 JOIN 附加表
    // 这里的写法更规范,但需要对整个SQL结构有了解
    // $where .= " AND addontable.brand = '".$this->searchArr['brand']."'";
    // 简单的模糊匹配方案
    $where .= " AND arc.body LIKE '%".$this->searchArr['brand']."%'";
}
// 将 $where 赋值给 $this->addSql
$this->addSql = $where;

第四步:URL伪静态优化 (可选但推荐)

URL中带有 和参数名不太美观,我们可以利用DedeCMS的伪静态规则将其美化。

将: /list.php?tid=1&typeid_filter=5&brand=苹果

美化成: /list/tid1/typeid5/brand苹果.html

  1. 修改 /include/helpers/helper_channelunit.php 找到 GetListUrl($typeid) 或类似的函数,修改生成列表URL的逻辑,使其包含所有GET参数,这通常比较复杂。

  2. 更简单的方法:修改 .htaccess (如果使用Apache) 在网站根目录的 .htaccess 文件中添加 Rewrite 规则。

    <IfModule mod_rewrite.c>
      RewriteEngine On
      # 将美化后的URL重写回真实的 list.php
      # 格式: /list/栏目ID/参数1名/参数1值/参数2名/参数2值.html
      RewriteRule ^list/tid([0-9]+)/(.+)\.html$ /list.php?tid=$1&$2
    </IfModule>

    这个规则会把 /list/tid10/typeid_filter5/brand苹果.html 这样的URL解析成 /list.php?tid=10&typeid_filter=5&brand=苹果

  3. 修改模板中的链接 在你的列表页模板中,所有指向当前页面的链接(如分页链接、筛选后的链接)都需要手动拼接成新的伪静态格式,这通常需要修改 arc.listview.class.php 中生成URL的部分,或者在模板中通过 {dede:field name='phpurl'/}/list.php?tid={dede:field name='typeid'/}&{$filter_str} 这样的方式动态构建,$filter_str 需要你自定义变量来保存拼接好的筛选参数。

总结与最佳实践

  1. 功能实现:核心是 模板表单 (GET提交) -> PHP处理 (拼接SQL) -> 数据库查询
  2. 性能LIKE '%...%' 会导致全表扫描,性能较差,如果数据量大,请务必为品牌等筛选字段建立独立的数据库字段和索引,并在SQL中使用 精确匹配。
  3. 扩展性:如果筛选条件很多,可以考虑将 GetSql() 方法中的 if 判断改写成循环,通过一个数组来管理所有筛选规则,这样代码会更简洁、易于维护。
  4. 安全性:在拼接SQL时,虽然DedeCMS底层有部分过滤,但最好还是对用户输入的参数进行转义或预处理,防止SQL注入。dede:sql$this->searchArr 传递过来的参数通常是经过处理的。

通过以上步骤,你就可以成功实现 DedeCMS 同时选择两个筛选条件的功能了,从最简单的 LIKE 匹配开始,实现功能后,再根据性能和规范要求进行优化。

-- 展开阅读全文 --
头像
斐波那契前20项和怎么用C语言算?
« 上一篇 02-05
C语言如何求n个数的最小公倍数?
下一篇 » 02-05

相关文章

取消
微信二维码
支付宝二维码

目录[+]