1

我正在开发一个应用程序,它将查找电子邮件收件箱并将特定电子邮件作为其功能的一部分保存。发生的情况是建立 imap 连接,然后检索所有设置为 UNSEEN 的电子邮件。每封电子邮件都会根据预定义的条件进行检查,如果满足,则将其保存到数据库中。这些条件可以由用户设置,可以是:

主题

  • 包含字符串
  • 不包含字符串

身体

  • 包含字符串
  • 不包含字符串

  • 具体地址

条件可以“链接”,例如:

FILTER WHERE  
Subject CONTAINS "Order Confirmation"
AND
Email FROM "billyjones26@gmail.com" OR "billyjones26@googlemail.com"

我在思考如何格式化和存储这些条件时遇到了麻烦。我需要有一个 GUI,用户可以在其中创建这些条件。

我的问题是我应该如何存储这些条件?即某种数据库表结构,或者可能转换为字符串格式并存储在单个表中。不限数量的用户需要有不限数量的条件,我需要知道有哪些运营商等等。

希望这是足够的信息!

* 为迈克尔编辑 *

所以我可以创造条件并保存它们。现在我正在检索它们并尝试匹配电子邮件。我创建了一个具有一个条件的过滤器:主题包含“测试”。只有一封电子邮件应该与此匹配,但不知何故,所有电子邮件都被添加到匹配的数组中。

我的控制器正在获取电子邮件/条件:

public function check_email(){
    $filters = $this->filters_model->get_filters($owner_id=1);
    foreach($filters->result() as $filter){
        $emails = $this->gmail->get_emails($mailbox_id = $filter->mailbox_id, $limit = 10);

        $matched = array();
        $conditions = unserialize($filter->conditions);

        foreach($emails as $email){
            if($conditions->isMet($email) == TRUE){
                $matched[] = $email;
            }
        }

        echo count($matched);
        echo '<pre>'.$filter->title.'<br /.';
        print_r($conditions);
        echo '</pre><br />-----';
        exit;
    }
}

键值先决条件.php

这似乎可以正常工作,因为 var_dumpstripos($subject, $this->value) !== FALSE;仅对 1 封电子邮件显示 TRUE。

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

class Keyvalueprerequisite {

    private $key;
    private $comparator;
    private $value;

    public function __construct($key, $comparator, $value){
        $this->key = $key;
        $this->comparator = $comparator;
        $this->value = $value;
    }


    public function isMet(&$context)
    {
        switch ($this->key) {

            case "subject":

                $subject = $context["subject"];
                if ($this->comparator === "in"){
                    return stripos($subject, $this->value) !== FALSE;
                } else if ($this->comparator === "!in") {
                    return stripos($subject, $this->value) === FALSE;
                }

                return FALSE;

                break;

            case "body":

                $body = $context["body"];

                if ($this->comparator === "in") {
                    return stripos($body, $this->value) !== FALSE;
                } else if ($this->comparator === "!in") {
                    return stripos($body, $this->value) === FALSE;
                }

                return FALSE;

                break;

            case "from_address":

                $from = $context["from"];

                if ($this->comparator === "=") {
                    return $this->value === $from;
                } else if ($this->comparator === "!=") {
                    return $this->value !== $from;
                } else{
                    return false;
                }

                break;

            default:
        }

        return FALSE;
    }

}

先决条件组.php

有些东西可能不太写在这里。var_dump 对$result = $result && $is_met10 封电子邮件中的每封都返回 true。

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

class Prerequisitegroup {

    private $type;
    private $prerequisites;

    public function __construct($type = 'AND'){
        $this->type = $type;
    }

    public function add(){
        foreach(func_get_args() as $prerequisite){
          $this->prerequisites[] = $prerequisite;
        }
    }

    public function isMet(&$context)
    {
        if (empty($this->prerequisites) === FALSE) {
            $result = TRUE;

            foreach ($this->prerequisites as $prerequisite) {
                $is_met = $prerequisite->isMet($context);
                if ($this->type === 'AND') {
                    $result = $result && $is_met;
                    if ($result === FALSE) {
                        return FALSE;
                    }
                } else {
                    $result = $result || $is_met;
                    if ($result === TRUE) {
                        return TRUE;
                    }
                }
            }
            return $result;
        }

        return TRUE;
    }


}

这些是我正在检查的条件:

string(3) "AND"
  ["prerequisites":"Prerequisitegroup":private]=>
  array(1) {
    [0]=>
    object(Prerequisitegroup)#23 (2) {
      ["type":"Prerequisitegroup":private]=>
      string(2) "OR"
      ["prerequisites":"Prerequisitegroup":private]=>
      array(1) {
        [0]=>
        object(Keyvalueprerequisite)#24 (3) {
          ["key":"Keyvalueprerequisite":private]=>
          string(7) "subject"
          ["comparator":"Keyvalueprerequisite":private]=>
          string(2) "in"
          ["value":"Keyvalueprerequisite":private]=>
          string(4) "TEST"
        }
      }
    }
  }
}
4

1 回答 1

1

对于 CMS,我通过将条件(先决条件)抽象为两个类来解决类似的问题: Prerequisite 和 PrerequisiteGroup (前者的子类,然后将它们序列化,或者更准确地说是 object,因为只有一个进入 BLOB在 MySQL 中。

这样做的好处是我可以简单地反序列化对象并调用一个isMet()函数,而不必担心附加条件的深度或复杂性。缺点当然是我无法对这些对象进行数据库查询。但这在这种特殊情况下不是问题,根据您自己的建议,我认为您的建议也不存在。

该类Prerequisite(或接口)实现了一种方法isMet($context),该方法告诉您您的条件是否为真。您的案例中的上下文将是要检查的 $email 。例如,如果来自电子邮件匹配“billyjones26@gmail.com”。

以简化的方式PrerequisiteGroup表示ANDOR。对条件进行分组的默认方式是

以下是创建和存储条件的示例:

$c1 = new KeyValuePrerequisite("EmailFrom", "=", "billyjones26@gmail.com");
$c2 = new KeyValuePrerequisite("EmailFrom", "=", "billyjones26@googlemail.com");
$c3 = new KeyValuePrerequisite("Subject", "in", "Order Confirmation");

$from_condition = new PrerequisiteGroup('or');
$from_condition->add($c1, $c2);

$final_condition = new PrerequisiteGroup($c3, $from_condition); // defaults to and

$db->query("INSERT INTO conditions SET user_id = %i, conditions = %l", $user_id, serialize($final_condition));

这是一个示例用法:

// Fetch conditions

$email_conditions = $user->getEmailConditions()

// Connect to your inbox and fetch relevant emails

$matching_emails = array();
foreach ($emails as $email) {
    if ($email_conditions->isMet($email) {
        $matching_emails[] = $email;
    }
}

必备接口:

interface Prerequisite 
{
    /**
     * Must return TRUE or FALSE.
     */
    public function isMet(&$context);
}

KeyValuePrerequisite 实现(在我的实现中,这实际上是一个抽象类,但出于您的目的,您可以在这里实现所有内容,您可以将其称为 EmailPrerequisite 或 EmailCondition):

class KeyValuePrerequisite extends PrerequisiteGroup
{
    protected $key;
    protected $comparator;
    protected $value;

    public function __construct($key, $comparator, $value = NULL)
    {
        $this->key        = $key;
        $this->comparator = $comparator;
        $this->value      = $value;
    }

    public function isMet(&$context)
    {
        switch ($this->key) {

            case "Subject":

                $subject = $context["subject"];

                if ($this->comparator === "in") }
                    return stripos($subject, $this->value) !== FALSE;
                } else if ($this->comparator === "not int") {
                    return stripos($subject, $this->value) === FALSE;
                }

                return FALSE;

                break;

            case "EmailFrom":

                $from = $context["from"];

                return $this->value === $from;

                break;

            default:
        }

        return FALSE;
    }
}

先决条件组实现:

class PrerequisiteGroup implements Prerequisite
{
    private $type;
    private $prerequisites;

    public function __construct($type = 'AND')
    {
        $this->type = $type;
    }

    public function add(Prerequisite $prerequisite)
    {
        if ($prerequisite instanceof Prerequisite) {
            $this->prerequisites[] = $prerequisite;
        } else {
            throw new Exception('Unknown Prerequisite type ' . get_class($prerequisite));
        }
    }

    public function isMet(&$context)
    {
        if (empty($this->prerequisites) === FALSE) {
            $result = $this->type === 'AND';
            foreach ($this->prerequisites as $prerequisite) {
                $is_met = $prerequisite->isMet($context);
                if ($this->type === 'AND') {
                    $result = $result && $is_met;
                    if ($result === FALSE) {
                        return FALSE;
                    }
                } else {
                    $result = $result || $is_met;
                    if ($result === TRUE) {
                        return TRUE;
                    }
                }
            }
            return $result;
        }

        return TRUE;
    }
}

图形用户界面

当涉及到 GUI 时,有几种方法/模式。我认为,对于与电子邮件相关的应用程序,最常见的做法是使用多行 AND 和 [+] 来添加更多条件的表达式:

Row 1: [select: subject] [select:contains] [input:"Order Confirmation"]

当涉及到时,from我们需要表达 OR。仅用行很难做到这一点。这是先决条件或条件组的概念变得方便的地方。您只需添加一个作为组的新行,并让用户选择使用 AND 或 OR。

外部组是 AND 组。

因此,GUI 元素很容易转换为代码,反之亦然——尤其是使用 KeyValuePrerequisite impl。的先决条件。

希望这有助于或至少激发一些想法来解决您的问题。

于 2012-08-27T14:40:07.380 回答