skip to Main Content

I have developed a Shopware 6 plugin that checks if an email is in a blacklist before allowing reviews. It works but currently does a database query for every email being checked. If I am in a scheduled task run that sends out 50 emails and I have 1000 entries with wildcard entries, this code won’t work anymore.

I would like to optimize the plugin to:

  • Support wildcard patterns in the blacklist (e.g. *@amazon.com)
  • Fetch the blacklist once and loop through it instead of separate queries

Here is the current code:

use MonologLogger;
use ShopwareCoreFrameworkContext;
use ShopwareCoreFrameworkDataAbstractionLayerEntityRepository;
use SwaProductReviewsComponentsLoggerHelper;
use ShopwareCoreFrameworkDataAbstractionLayerSearchCriteria;
use ShopwareCoreFrameworkDataAbstractionLayerSearchFilterEqualsFilter;


class MailWithBlacklist {
    private EntityRepository $blacklistRepository;
    protected LoggerHelper $loggerHelper;
    
    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
    {

        $criteria = new Criteria();
        $criteria->addFilter(new EqualsFilter('email', $email));

        
        $blacklistEntry = $this->blacklistRepository->search($criteria, $context)->first();

        $this->loggerHelper->addDirectRecord(Logger::DEBUG, 'end of isEmailBlacklisted' , ['blacklistEntry' => $blacklistEntry]);
        return $blacklistEntry !== null;
    }
}

How can I modify this code?

Any help is appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    To extend the plugin for wildcards and fetch the blacklist once, you can follow these steps:

    • Fetch the blacklist entries once and initialize $blacklistCache.
    • Loop through the $blacklistCache and use a helper method matchesWildcard to check for wildcard matches.
    • Add a helper method matchesWildcard to check the email against the wildcard pattern using preg_match method.
    class MailWithBlacklist {
        private $blacklistCache;
        private EntityRepository $blacklistRepository;
        protected LoggerHelper $loggerHelper;
        
        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
        {
         
            $criteria = new Criteria();
            $this->blacklistCache = $this->blacklistRepository->search($criteria, $context)->getEntities();
         
            foreach ($this->blacklistCache as $entry) {
             
                if ($this->matchesWildcard($email, $entry->getEmail())) {
     
                    return true;
                }
            }
            
            return false;
        }
        
        private function matchesWildcard(string $email, string $pattern): bool
        {
            $pattern = preg_quote($pattern, '/');
     
            $pattern = str_replace('*', '.*', $pattern);
            
            return (bool) preg_match("/$pattern/i", $email);
        }
    }
    

  2. For the part of the performance i don’t really see any issue with your approach. As you only make one additional DB call per web request i see no real performance issue here. The alternative would be to cache the blacklist e.g. in redis but that would make your plugin way more complicated as you also have to take care of invalidation of the blacklist, and you also have to implement the lookup in memory instead of using the DB for that.

    Regarding the flexibility of wildcards you can use an ContainsFilter which will translate to an LIKE %term% query under the hood.

    If you want to be even more flexible i wouldn’t use the shopware DAL repository, but rather use plain SQL, so out of the box you could ? as wildcards, but if you go in that direction beware of SQL injections.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search