You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shopware 6插件优化:邮箱黑名单通配符匹配与查询优化

优化方案

以下是修改后的代码,实现了一次性加载黑名单数据和通配符规则匹配的需求,同时避免了重复数据库查询:

use Monolog\Logger;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Swa\ProductReviews\Components\LoggerHelper;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;

class MailWithBlacklist {
    private EntityRepository $blacklistRepository;
    protected LoggerHelper $loggerHelper;
    // 类内缓存黑名单正则规则,避免重复查询数据库
    private ?array $blacklistPatterns = null;
    
    public function __construct(EntityRepository $blacklistRepository, LoggerHelper $loggerHelper) {
        $this->blacklistRepository = $blacklistRepository;
        $this->loggerHelper = $loggerHelper;
    }
    
    /**
     * 检查邮箱是否在黑名单(支持通配符规则)
     * @param string $email
     * @param Context $context
     * @return bool
     */
    public function isEmailBlacklisted(string $email, Context $context): bool
    {
        $patterns = $this->getBlacklistPatterns($context);

        // 遍历所有黑名单规则进行匹配
        foreach ($patterns as $pattern) {
            if (preg_match($pattern, $email)) {
                $this->loggerHelper->addDirectRecord(
                    Logger::DEBUG, 
                    'Email matched blacklist rule', 
                    ['email' => $email, 'rule' => $pattern]
                );
                return true;
            }
        }

        $this->loggerHelper->addDirectRecord(
            Logger::DEBUG, 
            'Email not found in blacklist', 
            ['email' => $email]
        );
        return false;
    }

    /**
     * 一次性加载黑名单数据并转换为正则匹配规则
     * @param Context $context
     * @return array
     */
    private function getBlacklistPatterns(Context $context): array
    {
        // 如果已有缓存,直接返回
        if ($this->blacklistPatterns !== null) {
            return $this->blacklistPatterns;
        }

        // 从数据库获取所有黑名单规则(仅加载email字段,减少数据传输)
        $criteria = new Criteria();
        $criteria->setFields(['email']);
        $blacklistEntries = $this->blacklistRepository->search($criteria, $context)->getEntities();

        $patterns = [];
        foreach ($blacklistEntries as $entry) {
            $rule = $entry->getEmail();
            if (empty($rule)) {
                continue;
            }

            // 将通配符规则转换为正则表达式:
            // 1. 转义正则特殊字符(如.、@)
            $regex = preg_quote($rule, '/');
            // 2. 将*替换为正则的任意匹配符.*
            $regex = str_replace('\*', '.*', $regex);
            // 3. 添加首尾锚点,确保完整匹配邮箱,忽略大小写
            $patterns[] = '/^' . $regex . '$/i';
        }

        // 缓存规则
        $this->blacklistPatterns = $patterns;
        return $patterns;
    }
}

关键修改说明

  1. 一次性加载黑名单:

    • 通过getBlacklistPatterns方法一次性从数据库拉取所有黑名单规则,避免每次检查都发起查询。
    • 使用类内属性$blacklistPatterns缓存转换后的正则规则,重复调用时直接复用。
  2. 通配符支持:

    • 将黑名单中的*通配符转换为正则表达式的.*(匹配任意字符),同时转义邮箱中的特殊正则字符(如.、@)。
    • 采用忽略大小写的完整匹配(^和$锚点),确保规则精准匹配邮箱格式。
  3. 性能优化:

    • 查询时仅加载email字段,减少数据库传输的数据量。
    • 内存中遍历匹配,在批量检查场景(如50封邮件的定时任务)下,性能远优于多次数据库查询。

额外建议

如果需要支持黑名单规则的实时更新(如管理员修改黑名单后立即生效),可以:

  • 移除类内缓存,每次调用getBlacklistPatterns时重新拉取数据(适合实时性要求高的场景)。
  • 集成Shopware的缓存组件(如Symfony Cache),设置合理的缓存过期时间,或在黑名单实体更新时触发缓存清除。

内容的提问来源于stack exchange,提问作者mlodhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:56:19